Docker MySQL 8.0.45 性能优化配置文档

环境 : Docker mysql8 容器 | 服务器: 192.168.65.100


一、硬件环境

项目 配置
CPU 4 核
内存 7.7 GB(可用 ~6.5 GB)
磁盘 97 GB
Docker 资源限制 无限制(CPU=0, Mem=0)
MySQL 版本 8.0.45(官方镜像)

二、配置文件架构

复制代码
宿主机                         容器内
──────────────────────────────────────────
/data/mysql8/conf/  ──bind──▶ /etc/mysql/conf.d/
  ├── max_allowed_packet.cnf       (由 my.cnf 中 !includedir 自动加载)
  └── performance.cnf

/data/mysql8/data/  ──bind──▶ /var/lib/mysql/

所有配置通过 docker inspect mysql8 确认挂载正确,容器重启/重建均不丢失。


三、参数持久化方案

3.1 为什么 SET GLOBAL 不持久

MySQL 中修改参数有两种方式:

方式 示例 生效范围 容器重启后
SET GLOBAL SET GLOBAL max_allowed_packet=512M; 当前运行实例,内存中 丢失,恢复默认值
配置文件 max_allowed_packet=512M 写入 my.cnf 启动时读取,全局生效 永久生效

因此所有性能参数必须写入配置文件 ,而非仅靠 SET GLOBAL

3.2 Docker 绑定挂载 → 持久化

MySQL 官方镜像的 my.cnf 末尾有指令:

ini 复制代码
!includedir /etc/mysql/conf.d/

这意味着放在 /etc/mysql/conf.d/ 目录下的任何 .cnf 文件都会被自动加载

关键:该目录通过 Docker bind mount 映射到宿主机,因此文件在宿主机上创建即可持久化:

复制代码
宿主机文件                     挂载关系        容器内加载路径
────────────────────────────────────────────────────────────
/data/mysql8/conf/     ──bind mount──▶  /etc/mysql/conf.d/
  └─ performance.cnf                      └─ 被 my.cnf 的 !includedir 自动加载

docker inspect 验证挂载配置:

bash 复制代码
docker inspect mysql8 --format '{{json .Mounts}}' | python3 -m json.tool

输出示例:

json 复制代码
[
    {
        "Type": "bind",
        "Source": "/data/mysql8/conf",
        "Destination": "/etc/mysql/conf.d",
        "RW": true
    },
    {
        "Type": "bind",
        "Source": "/data/mysql8/data",
        "Destination": "/var/lib/mysql",
        "RW": true
    }
]

Source = 宿主机目录,文件存这里就永远不会丢。

3.3 创建持久化配置(完整操作)

bash 复制代码
# Step 1: 在宿主机创建配置文件
cat > /data/mysql8/conf/performance.cnf << 'EOF'
[mysqld]
innodb_buffer_pool_size = 2G
innodb_buffer_pool_instances = 2
innodb_log_file_size = 256M
# ... 其他参数 ...
max_allowed_packet = 512M
EOF

# Step 2: 验证容器内可见
docker exec mysql8 cat /etc/mysql/conf.d/performance.cnf

# Step 3: 优雅关闭 + 重启(innodb_log_file_size 变更需额外处理)
docker exec mysql8 mysql -uroot -p -e "SET GLOBAL innodb_fast_shutdown=0;"
docker exec mysql8 rm -f /var/lib/mysql/ib_logfile*
docker restart mysql8

# Step 4: 验证参数已从配置文件加载
docker exec mysql8 mysql -uroot -p -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"
# 预期: 2147483648 (2G)

3.4 持久化验证

重启容器后确认参数来自配置文件而非默认值:

bash 复制代码
# 重启
docker restart mysql8

# 验证关键参数仍为优化值
docker exec mysql8 mysql -uroot -p -e "
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW VARIABLES LIKE 'innodb_log_file_size';
SHOW VARIABLES LIKE 'max_allowed_packet';
"
验证点 默认值(重启后如未持久化) 持久化后期望
innodb_buffer_pool_size 134217728 (128M) 2147483648 (2G)
innodb_log_file_size 50331648 (48M) 268435456 (256M)
max_allowed_packet 67108864 (64M) 536870912 (512M)

如果重启后值与期望不符,说明配置文件未被正确加载,检查:

  1. docker inspect 确认挂载路径正确
  2. docker exec mysql8 ls /etc/mysql/conf.d/ 确认文件存在
  3. docker exec mysql8 mysqld --verbose --help 2>/dev/null | grep -A1 "conf.d" 确认 !includedir 生效

3.5 当前已持久化的配置文件

复制代码
/data/mysql8/conf/
├── max_allowed_packet.cnf    # [mysqld] max_allowed_packet=512M
└── performance.cnf           # [mysqld] 全部 InnoDB/连接/缓存优化参数

两个文件互不冲突,MySQL 会按文件名字母顺序加载(后加载的同名参数覆盖先加载的)。


四、优化前现状分析

MySQL 8.0.45 官方镜像的全部默认参数,运行在 7.7GB 服务器上存在严重浪费:

关键问题 默认值 浪费程度
Buffer Pool 仅 128M 7.7GB 总内存利用率 1.6% 🔴 严重
Redo Log 仅 50M 高写入场景频繁 checkpoint 🟡 中等
IO 容量仅 200 未利用 SSD 吞吐能力 🟡 中等
每次事务都刷盘 开发/测试环境过度安全 🟡 中等
线程缓存仅 9 频繁创建/销毁线程 🟢 轻微
慢查询日志关闭 无法排查性能问题 🟢 轻微

五、优化参数详解

4.1 InnoDB 核心优化 🔥

参数 说明 优化前 优化后 影响
innodb_buffer_pool_size 数据和索引缓存,最重要的性能参数 128M 2G 缓存命中率从 ~30% 提升至 95%+,减少磁盘 IO
innodb_buffer_pool_instances Buffer Pool 分区数 1 2 多核并发访问时减少锁竞争
innodb_log_file_size Redo Log 单个文件大小 50M 256M 减少 checkpoint 频率,写入更平滑
innodb_log_buffer_size Redo Log 内存缓冲区 16M 64M 批量写入磁盘,减少小 IO
innodb_io_capacity 后台 IO 操作吞吐上限 200 1000 充分利用磁盘吞吐能力
innodb_io_capacity_max 紧急情况下 IO 上限 2000 3000 突发 IO 允许更高吞吐
innodb_flush_log_at_trx_commit 事务日志刷盘策略 1 2 ⚠️ 1=每次提交刷盘(最安全),2=每秒刷盘(平衡)
innodb_flush_method 数据文件刷盘方式 fsync O_DIRECT 绕过 OS 缓存,避免双重缓存
innodb_flush_log_at_trx_commit 重要说明
复制代码
值为 0:每秒写入日志并刷盘(性能最高,可能丢 1 秒数据)
值为 1:每次提交都写入并刷盘(最安全,性能最低)  ← 默认
值为 2:每次提交写入,每秒刷盘(平衡方案)        ← 当前

当前选择 2 的理由 : 这是开发/内部使用环境,对极端数据安全性要求不高,

每秒最多丢失 1 秒事务数据可接受,但写性能提升 5~10 倍。

如需最高安全性可改为 1。

内存分配分析
复制代码
服务器总内存:     7.7 GB
系统预留:         ~1.0 GB
其他服务:         ~3.0 GB
MySQL Buffer Pool: 2.0 GB
剩余可用:         ~1.7 GB

4.2 连接与线程

参数 说明 优化前 优化后
max_connections 最大连接数 151 300
thread_cache_size 线程缓存 9 32
wait_timeout 非交互连接超时(秒) 28800 (8h) 3600 (1h)
interactive_timeout 交互连接超时(秒) 28800 (8h) 3600 (1h)

wait_timeout 设为 3600s 可自动清理长时间空闲连接,避免连接数耗尽。

4.3 表缓存

参数 说明 优化前 优化后
table_open_cache 打开表缓存数量 4000 4000
table_definition_cache 表定义缓存 2000 4000

当前 126 张表,4000 足够。每张表打开消耗约 4KB,总消耗约 16MB。

4.4 内存临时表与排序

参数 说明 优化前 优化后 备注
tmp_table_size 内存临时表大小 16M 64M 超过此值转为磁盘临时表
max_heap_table_size MEMORY 引擎表最大大小 16M 64M 与 tmp_table_size 保持一致
sort_buffer_size 排序缓冲区 256K 512K 每个需要排序的会话分配
join_buffer_size JOIN 缓冲区 256K 512K 每个需要 JOIN 的会话分配
read_buffer_size 顺序读缓冲区 128K 256K 全表扫描时使用
read_rnd_buffer_size 随机读缓冲区 256K 512K ORDER BY 后读取使用

⚠️ sort_buffer_sizejoin_buffer_sizeper-session (每个连接)的,

不要设太大。当前值在 300 连接上限下最坏情况内存占用:300 × (512K+512K+256K+512K) ≈ 525MB

4.5 Binlog 日志

参数 说明 优化前 优化后
log_bin 启用二进制日志 ON ON
binlog_format binlog 格式 ROW ROW
sync_binlog binlog 刷盘频率 1 (每次) 1 (保持)
binlog_cache_size 事务 binlog 缓存 32K 1M
binlog_expire_logs_seconds binlog 自动清理 30天 7天

binlog_expire_logs_seconds 从 30 天缩短到 7 天,减少磁盘占用。

4.6 监控与诊断

参数 说明 优化前 优化后
slow_query_log 慢查询日志开关 OFF ON
long_query_time 慢查询阈值(秒) 10 2
slow_query_log_file 慢查询日志路径 默认 /var/lib/mysql/slow.log

超过 2 秒的查询会被记录,便于后续排查和优化。

4.7 其他

参数 说明 优化前 优化后
max_allowed_packet 最大数据包 64M 512M

导入 127MB 的 test.sql 时遇到 ERR 2006 MySQL server has gone away

就是此参数过小导致。512M 足以应对大型 INSERT 语句。


六、完整配置文件

以下为 /data/mysql8/conf/performance.cnf 的实际内容:

ini 复制代码
[mysqld]

# ===== InnoDB 核心优化 =====
# Buffer Pool: 最重要参数,设为可用内存 60-70%
# 当前服务器 7.7G 总内存,分配 2G 给 MySQL
innodb_buffer_pool_size = 2G
innodb_buffer_pool_instances = 2

# Redo Log: 增大减少 checkpoint 频率
innodb_log_file_size = 256M
innodb_log_buffer_size = 64M

# IO 容量: SSD 推荐 1000-2000,HDD 保持 200
innodb_io_capacity = 1000
innodb_io_capacity_max = 3000

# 刷新策略: 1=每次刷盘(最安全), 2=每秒刷盘(平衡)
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT

# ===== 连接与线程 =====
thread_cache_size = 32
max_connections = 300
wait_timeout = 3600
interactive_timeout = 3600

# ===== 表缓存 =====
table_open_cache = 4000
table_definition_cache = 4000

# ===== 临时表 =====
tmp_table_size = 64M
max_heap_table_size = 64M

# ===== 排序与 JOIN 缓冲 (per-session) =====
sort_buffer_size = 512K
join_buffer_size = 512K
read_buffer_size = 256K
read_rnd_buffer_size = 512K

# ===== 慢查询日志 =====
slow_query_log = ON
long_query_time = 2
slow_query_log_file = /var/lib/mysql/slow.log

# ===== Binlog =====
binlog_cache_size = 1M
binlog_expire_logs_seconds = 604800

# ===== 其他 =====
max_allowed_packet = 512M

七、变更 innodb_log_file_size 的特殊步骤

修改 innodb_log_file_size 时,MySQL 不会自动调整已存在的 redo log 文件,

必须手动删除旧文件后重启:

bash 复制代码
# 1. 优雅关闭 MySQL (完整刷盘)
docker exec mysql8 mysql -uroot -p -e "SET GLOBAL innodb_fast_shutdown=0;"

# 2. 删除旧 redo log 文件
docker exec mysql8 rm -f /var/lib/mysql/ib_logfile*

# 3. 重启容器(会自动创建新大小的 redo log)
docker restart mysql8

⚠️ 跳过步骤 2 会导致 MySQL 启动失败,报错 redo log size mismatch。


八、验证优化效果

bash 复制代码
# 确认所有参数已生效
docker exec mysql8 mysql -uroot -p -e "
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SHOW VARIABLES LIKE 'innodb_log_file_size';
SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit';
SHOW VARIABLES LIKE 'innodb_io_capacity';
SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'max_allowed_packet';
"

预期输出:

参数
innodb_buffer_pool_size 2147483648 (2G)
innodb_log_file_size 268435456 (256M)
innodb_flush_log_at_trx_commit 2
innodb_io_capacity 1000
slow_query_log ON
max_allowed_packet 536870912 (512M)

九、优化效果预估

指标 优化前 优化后
Buffer Pool 命中率 ~30% 95%+
写入吞吐量 基准值 5~10 倍
Checkpoint 频率 频繁 低频
慢查询可见性 2 秒以上自动记录
最大并发连接 151 300
binlog 磁盘占用 30 天 7 天

十、后续建议

  1. 定期查看慢查询日志 : docker exec mysql8 mysqldumpslow /var/lib/mysql/slow.log

  2. 监控 Buffer Pool 命中率:

    sql 复制代码
    SHOW STATUS LIKE 'Innodb_buffer_pool_read%';
    -- read_requests / (reads + read_requests) 应 > 95%
  3. 根据业务增长调整 : 如果表数据量增长到接近 2G,考虑酌情增大 innodb_buffer_pool_size

  4. 磁盘 I/O 压力大时 : 可提升 innodb_io_capacity 到 2000


📄 配置文件路径: /data/mysql8/conf/performance.cnf

🖥️ 目标服务器: 192.168.65.100

🐳 容器名称: mysql8

相关推荐
一条泥憨鱼1 小时前
深入理解 MySQL 索引:原理、分类与优化实战
数据库·mysql
一条泥憨鱼1 小时前
详解MySQL事务(超详细版)
java·数据库·mysql·spring·maven·后端开发
j7~1 小时前
【MYSQL】 数据库的常见数据类型--详解
数据库·mysql·decimal·varchar·数据库的基本类型
rising start10 小时前
二、全面理解MySQL架构
mysql·架构
bqq1986102611 小时前
MySQL性能优化
mysql·mysql优化
雨辰AI12 小时前
SpringBoot3 + 人大金仓读写分离 + 分库分表 + 集群高可用 全栈实战
java·数据库·mysql·政务
长城202413 小时前
关于MySql的ONLY_FULL_GROUP_BY问题
数据库·mysql·聚合列
常常有13 小时前
MySQL 底层执行原理:输入SQL语句到两阶段提交
数据库·sql·mysql
海市公约14 小时前
MySQL更新语句执行全流程:从Buffer Pool修改到二阶段提交
数据库·mysql·binlog·innodb·undo log·二阶段提交·update执行原理