Docker MySQL 8.0.45性能優(yōu)化配置文檔方式
- 環(huán)境:Docker mysql8 容器
- 服務(wù)器:192.168.65.100
一、硬件環(huán)境
| 項目 | 配置 |
|---|---|
| CPU | 4 核 |
| 內(nèi)存 | 7.7 GB(可用 ~6.5 GB) |
| 磁盤 | 97 GB |
| Docker 資源限制 | 無限制(CPU=0, Mem=0) |
| MySQL 版本 | 8.0.45(官方鏡像) |
二、配置文件架構(gòu)
宿主機 容器內(nèi) ────────────────────────────────────────── /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 確認(rèn)掛載正確,容器重啟/重建均不丟失。
三、參數(shù)持久化方案
3.1 為什么 SET GLOBAL 不持久
MySQL 中修改參數(shù)有兩種方式:
| 方式 | 示例 | 生效范圍 | 容器重啟后 |
|---|---|---|---|
| SET GLOBAL | SET GLOBAL max_allowed_packet=512M; | 當(dāng)前運行實例,內(nèi)存中 | ? 丟失,恢復(fù)默認(rèn)值 |
| 配置文件 | max_allowed_packet=512M 寫入 my.cnf | 啟動時讀取,全局生效 | ? 永久生效 |
因此所有性能參數(shù)必須寫入配置文件,而非僅靠 SET GLOBAL。
3.2 Docker 綁定掛載 → 持久化
MySQL 官方鏡像的 my.cnf 末尾有指令:
!includedir /etc/mysql/conf.d/
這意味著放在 /etc/mysql/conf.d/ 目錄下的任何 .cnf 文件都會被自動加載。
關(guān)鍵:該目錄通過 Docker bind mount 映射到宿主機,因此文件在宿主機上創(chuàng)建即可持久化:
宿主機文件 掛載關(guān)系 容器內(nèi)加載路徑 ──────────────────────────────────────────────────────────── /data/mysql8/conf/ ──bind mount──? /etc/mysql/conf.d/ └─ performance.cnf └─ 被 my.cnf 的 !includedir 自動加載
用 docker inspect 驗證掛載配置:
docker inspect mysql8 --format '{{json .Mounts}}' | python3 -m json.tool
輸出示例:
[
{
"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 = 宿主機目錄,文件存這里就永遠(yuǎn)不會丟。
3.3 創(chuàng)建持久化配置(完整操作)
# Step 1: 在宿主機創(chuàng)建配置文件 cat > /data/mysql8/conf/performance.cnf << 'EOF' [mysqld] innodb_buffer_pool_size = 2G innodb_buffer_pool_instances = 2 innodb_log_file_size = 256M # ... 其他參數(shù) ... max_allowed_packet = 512M EOF # Step 2: 驗證容器內(nèi)可見 docker exec mysql8 cat /etc/mysql/conf.d/performance.cnf # Step 3: 優(yōu)雅關(guān)閉 + 重啟(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: 驗證參數(shù)已從配置文件加載 docker exec mysql8 mysql -uroot -p -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';" # 預(yù)期: 2147483648 (2G)
3.4 持久化驗證
重啟容器后確認(rèn)參數(shù)來自配置文件而非默認(rèn)值:
# 重啟 docker restart mysql8 # 驗證關(guān)鍵參數(shù)仍為優(yōu)化值 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'; "
| 驗證點 | 默認(rèn)值(重啟后如未持久化) | 持久化后期望 |
|---|---|---|
| innodb_buffer_pool_size | 134217728 (128M) | 2147483648 (2G) |
| innodb_log_file_size | 50331648 (48M) | 268435456 (256M) |
| max_allowed_packet | 67108864 (64M) | 536870912 (512M) |
如果重啟后值與期望不符,說明配置文件未被正確加載,檢查:
docker inspect確認(rèn)掛載路徑正確docker exec mysql8 ls /etc/mysql/conf.d/確認(rèn)文件存在docker exec mysql8 mysqld --verbose --help 2>/dev/null | grep -A1 "conf.d"確認(rèn)!includedir生效
3.5 當(dāng)前已持久化的配置文件
/data/mysql8/conf/ ├── max_allowed_packet.cnf # [mysqld] max_allowed_packet=512M └── performance.cnf # [mysqld] 全部 InnoDB/連接/緩存優(yōu)化參數(shù)
兩個文件互不沖突,MySQL 會按文件名字母順序加載(后加載的同名參數(shù)覆蓋先加載的)。
四、優(yōu)化前現(xiàn)狀分析
MySQL 8.0.45 官方鏡像的全部默認(rèn)參數(shù),運行在 7.7GB 服務(wù)器上存在嚴(yán)重浪費:
| 關(guān)鍵問題 | 默認(rèn)值 | 浪費程度 |
|---|---|---|
| Buffer Pool 僅 128M | 7.7GB 總內(nèi)存利用率 1.6% | ?? 嚴(yán)重 |
| Redo Log 僅 50M | 高寫入場景頻繁 checkpoint | ?? 中等 |
| IO 容量僅 200 | 未利用 SSD 吞吐能力 | ?? 中等 |
| 每次事務(wù)都刷盤 | 開發(fā)/測試環(huán)境過度安全 | ?? 中等 |
| 線程緩存僅 9 | 頻繁創(chuàng)建/銷毀線程 | ?? 輕微 |
| 慢查詢?nèi)罩娟P(guān)閉 | 無法排查性能問題 | ?? 輕微 |
五、優(yōu)化參數(shù)詳解
4.1 InnoDB 核心優(yōu)化
| 參數(shù) | 說明 | 優(yōu)化前 | 優(yōu)化后 | 影響 |
|---|---|---|---|---|
| innodb_buffer_pool_size | 數(shù)據(jù)和索引緩存,最重要的性能參數(shù) | 128M | 2G | 緩存命中率從 ~30% 提升至 95%+,減少磁盤 IO |
| innodb_buffer_pool_instances | Buffer Pool 分區(qū)數(shù) | 1 | 2 | 多核并發(fā)訪問時減少鎖競爭 |
| innodb_log_file_size | Redo Log 單個文件大小 | 50M | 256M | 減少 checkpoint 頻率,寫入更平滑 |
| innodb_log_buffer_size | Redo Log 內(nèi)存緩沖區(qū) | 16M | 64M | 批量寫入磁盤,減少小 IO |
| innodb_io_capacity | 后臺 IO 操作吞吐上限 | 200 | 1000 | 充分利用磁盤吞吐能力 |
| innodb_io_capacity_max | 緊急情況下 IO 上限 | 2000 | 3000 | 突發(fā) IO 允許更高吞吐 |
| innodb_flush_log_at_trx_commit | 事務(wù)日志刷盤策略 | 1 | 2 | ?? 1=每次提交刷盤(最安全),2=每秒刷盤(平衡) |
| innodb_flush_method | 數(shù)據(jù)文件刷盤方式 | fsync | O_DIRECT | 繞過 OS 緩存,避免雙重緩存 |
innodb_flush_log_at_trx_commit 重要說明
值為 0:每秒寫入日志并刷盤(性能最高,可能丟 1 秒數(shù)據(jù)) 值為 1:每次提交都寫入并刷盤(最安全,性能最低) ← 默認(rèn) 值為 2:每次提交寫入,每秒刷盤(平衡方案) ← 當(dāng)前
- 當(dāng)前選擇 2 的理由: 這是開發(fā)/內(nèi)部使用環(huán)境,對極端數(shù)據(jù)安全性要求不高,
- 每秒最多丟失 1 秒事務(wù)數(shù)據(jù)可接受,但寫性能提升 5~10 倍。
- 如需最高安全性可改為 1。
內(nèi)存分配分析
服務(wù)器總內(nèi)存: 7.7 GB 系統(tǒng)預(yù)留: ~1.0 GB 其他服務(wù): ~3.0 GB MySQL Buffer Pool: 2.0 GB 剩余可用: ~1.7 GB
4.2 連接與線程
| 參數(shù) | 說明 | 優(yōu)化前 | 優(yōu)化后 |
|---|---|---|---|
| max_connections | 最大連接數(shù) | 151 | 300 |
| thread_cache_size | 線程緩存 | 9 | 32 |
| wait_timeout | 非交互連接超時(秒) | 28800 (8h) | 3600 (1h) |
| interactive_timeout | 交互連接超時(秒) | 28800 (8h) | 3600 (1h) |
wait_timeout 設(shè)為 3600s 可自動清理長時間空閑連接,避免連接數(shù)耗盡。
4.3 表緩存
| 參數(shù) | 說明 | 優(yōu)化前 | 優(yōu)化后 |
|---|---|---|---|
| table_open_cache | 打開表緩存數(shù)量 | 4000 | 4000 |
| table_definition_cache | 表定義緩存 | 2000 | 4000 |
當(dāng)前 126 張表,4000 足夠。每張表打開消耗約 4KB,總消耗約 16MB。
4.4 內(nèi)存臨時表與排序
| 參數(shù) | 說明 | 優(yōu)化前 | 優(yōu)化后 | 備注 |
|---|---|---|---|---|
| tmp_table_size | 內(nèi)存臨時表大小 | 16M | 64M | 超過此值轉(zhuǎn)為磁盤臨時表 |
| max_heap_table_size | MEMORY 引擎表最大大小 | 16M | 64M | 與 tmp_table_size 保持一致 |
| sort_buffer_size | 排序緩沖區(qū) | 256K | 512K | 每個需要排序的會話分配 |
| join_buffer_size | JOIN 緩沖區(qū) | 256K | 512K | 每個需要 JOIN 的會話分配 |
| read_buffer_size | 順序讀緩沖區(qū) | 128K | 256K | 全表掃描時使用 |
| read_rnd_buffer_size | 隨機讀緩沖區(qū) | 256K | 512K | ORDER BY 后讀取使用 |
sort_buffer_size 和 join_buffer_size 是 per-session(每個連接)的,
不要設(shè)太大。當(dāng)前值在 300 連接上限下最壞情況內(nèi)存占用:300 × (512K+512K+256K+512K) ≈ 525MB。
4.5 Binlog 日志
| 參數(shù) | 說明 | 優(yōu)化前 | 優(yōu)化后 |
|---|---|---|---|
| log_bin | 啟用二進制日志 | ON | ON |
| binlog_format | binlog 格式 | ROW | ROW |
| sync_binlog | binlog 刷盤頻率 | 1 (每次) | 1 (保持) |
| binlog_cache_size | 事務(wù) binlog 緩存 | 32K | 1M |
| binlog_expire_logs_seconds | binlog 自動清理 | 30天 | 7天 |
binlog_expire_logs_seconds 從 30 天縮短到 7 天,減少磁盤占用。
4.6 監(jiān)控與診斷
| 參數(shù) | 說明 | 優(yōu)化前 | 優(yōu)化后 |
|---|---|---|---|
| slow_query_log | 慢查詢?nèi)罩鹃_關(guān) | OFF | ON |
| long_query_time | 慢查詢閾值(秒) | 10 | 2 |
| slow_query_log_file | 慢查詢?nèi)罩韭窂?/td> | 默認(rèn) | /var/lib/mysql/slow.log |
超過 2 秒的查詢會被記錄,便于后續(xù)排查和優(yōu)化。
4.7 其他
| 參數(shù) | 說明 | 優(yōu)化前 | 優(yōu)化后 |
|---|---|---|---|
| max_allowed_packet | 最大數(shù)據(jù)包 | 64M | 512M |
導(dǎo)入 127MB 的 test.sql 時遇到 ERR 2006 MySQL server has gone away,就是此參數(shù)過小導(dǎo)致。
512M 足以應(yīng)對大型 INSERT 語句。
六、完整配置文件
以下為 /data/mysql8/conf/performance.cnf 的實際內(nèi)容:
[mysqld] # ===== InnoDB 核心優(yōu)化 ===== # Buffer Pool: 最重要參數(shù),設(shè)為可用內(nèi)存 60-70% # 當(dāng)前服務(wù)器 7.7G 總內(nèi)存,分配 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 # ===== 慢查詢?nèi)罩?===== 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 不會自動調(diào)整已存在的 redo log 文件,
必須手動刪除舊文件后重啟:
# 1. 優(yōu)雅關(guān)閉 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. 重啟容器(會自動創(chuàng)建新大小的 redo log) docker restart mysql8
跳過步驟 2 會導(dǎo)致 MySQL 啟動失敗,報錯 redo log size mismatch。
八、驗證優(yōu)化效果
# 確認(rèn)所有參數(shù)已生效 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'; "
預(yù)期輸出:
| 參數(shù) | 值 |
|---|---|
| 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) |
九、優(yōu)化效果預(yù)估
| 指標(biāo) | 優(yōu)化前 | 優(yōu)化后 |
|---|---|---|
| Buffer Pool 命中率 | ~30% | 95%+ |
| 寫入吞吐量 | 基準(zhǔn)值 | 5~10 倍 |
| Checkpoint 頻率 | 頻繁 | 低頻 |
| 慢查詢可見性 | 無 | 2 秒以上自動記錄 |
| 最大并發(fā)連接 | 151 | 300 |
| binlog 磁盤占用 | 30 天 | 7 天 |
十、后續(xù)建議
定期查看慢查詢?nèi)罩?/strong>:
docker exec mysql8 mysqldumpslow /var/lib/mysql/slow.log
監(jiān)控 Buffer Pool 命中率:
SHOW STATUS LIKE 'Innodb_buffer_pool_read%'; -- read_requests / (reads + read_requests) 應(yīng) > 95%
根據(jù)業(yè)務(wù)增長調(diào)整:如果表數(shù)據(jù)量增長到接近 2G,考慮酌情增大 innodb_buffer_pool_size
磁盤 I/O 壓力大時:可提升 innodb_io_capacity 到 2000
- 配置文件路徑:
/data/mysql8/conf/performance.cnf - 目標(biāo)服務(wù)器:
192.168.65.100 - 容器名稱:
mysql8
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
手把手教你docker部署(使用docker-compose)教程
使用 Docker Compose 可以輕松、高效的管理容器,下面這篇文章主要給大家介紹了關(guān)于手把手教你docker部署(使用docker-compose)的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01
Docker Consul概述以及集群環(huán)境搭建步驟(圖文詳解)
本文主要介紹了Docker-Consul概述以及集群環(huán)境搭建步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-12-12

