目录
[1. 系统层面排查](#1. 系统层面排查)
[2. 数据库层面分析](#2. 数据库层面分析)
[1. sync_binlog 参数优化](#1. sync_binlog 参数优化)
[2. innodb_flush_log_at_trx_commit 参数调整](#2. innodb_flush_log_at_trx_commit 参数调整)
[1. 日志文件位置调整](#1. 日志文件位置调整)
[2. 生产环境核心参数配置模板](#2. 生产环境核心参数配置模板)
[3. 突发 IO 高负载应急响应方案](#3. 突发 IO 高负载应急响应方案)
一、线上告警
某一天,生产环境监控系统突然报警:MySQL 磁盘 IOPS 持续超过 15000,平均响应时间突破 500ms,慢查询数量大量增加。登录数据库服务器发现:
- 磁盘利用率长期维持在 98% 以上
iostat -x 1
显示%util
持续 100%- MySQL 进程 CPU 使用率达 90%,但大部分时间处于
iowait
状态
二、问题诊断
1. 系统层面排查
ruby
# 查看系统整体IO情况
$ iostat -x 1 10
Linux 5.4.0-150-generic (mysql-prod-01) 03/22/2025 _x86_64_ (32 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
7.2 0.00 4.5 12.3 0.0 76.0
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.0 0.0 0.0 14828.0 0.0 245440.0 33.1 7.5 0.5 0.0 0.5 0.0 99.8
sdb 0.0 4567.0 230.0 2800.0 18400.0 224000.0 152.8 12.5 4.1 2.8 4.2 0.3 99.9
# 监控MySQL进程IO情况
$ pidstat -d 1
Linux 5.4.0-150-generic (mysql-prod-01) 03/22/2025 _x86_64_ (32 CPU)
15:30:01 UID PID kB_rd/s kB_wr/s kB_ccwr/s Command
15:30:02 0 12345 0.00 245760.00 0.00 mysqld
# 分析IO请求分布
$ iotop -o
Total DISK READ : 0.00 B/s | Total DISK WRITE : 240.00 M/s
Actual DISK READ: 0.00 B/s | Actual DISK WRITE: 240.00 M/s
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
12345 be/4 mysql 0.00 B/s 240.00 M/s 0.00 % 99.99 % mysqld --defaults-file=/etc/mysql/my.cnf
通过上述命令发现:
- MySQL 进程(PID 12345)占用了 92% 的磁盘写 IO
- 大部分 IO 集中在
/var/lib/mysql/ib_logfile0
和/var/lib/mysql/mysql-bin.000001
文件
2. 数据库层面分析
sql
-- 查看InnoDB日志等待情况
mysql> SHOW ENGINE INNODB STATUS\G
*************************** 1. row ***************************
Type: InnoDB
Name:
Status:
=====================================
2025-03-22 15:35:23 0x7f8a1c000700 INNODB MONITOR OUTPUT
=====================================
[...]
--------
FILE I/O
--------
I/O thread 0 state: waiting for completed aio requests (insert buffer thread)
I/O thread 1 state: waiting for completed aio requests (log thread)
Pending normal aio reads: [0, 0, 0, 0] , aio writes: [0, 0, 0, 0] ,
ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync) log: 0; buffer pool: 0
288334 OS file reads, 1234567 OS file writes, 876543 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 245.00 writes/s, 120.00 fsyncs/s
[...]
-- 分析慢查询日志
$ pt-query-digest /var/log/mysql/slow.log > slow_query_report.txt
关键发现:
- InnoDB 日志等待事件占比达 68%
- 大量简单 INSERT 语句执行时间超过 200ms
- binlog 写入等待成为性能瓶颈
三、参数调优
1. sync_binlog 参数优化
原配置:
sql
mysql> SHOW VARIABLES LIKE '%sync_binlog%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sync_binlog | 1 |
+---------------+-------+
1 row in set (0.00 sec)
sync_binlog=1
意味着每次事务提交都会强制将 binlog 写入磁盘,这是导致高 IO 的主要原因。在高并发写入场景下,这种配置会严重影响性能。
优化措施:
sql
-- 临时调整(立即生效)
mysql> SET GLOBAL sync_binlog=1000;
Query OK, 0 rows affected (0.00 sec)
-- 验证修改结果
mysql> SHOW VARIABLES LIKE '%sync_binlog%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sync_binlog | 1000 |
+---------------+-------+
1 row in set (0.00 sec)
-- 持久化配置(修改my.cnf)
$ sudo vi /etc/mysql/my.cnf
[mysqld]
sync_binlog=1000
-- 重启MySQL服务使配置永久生效
$ sudo systemctl restart mysql
调整后效果:
- 磁盘 IOPS 从 15000 降至 8000
- 写入事务平均响应时间从 520ms 降至 85ms
2. innodb_flush_log_at_trx_commit 参数调整
原配置:
sql
mysql> SHOW VARIABLES LIKE '%innodb_flush_log%';
+--------------------------------+-------+
| Variable_name | Value |
+--------------------------------+-------+
| innodb_flush_log_at_trx_commit | 1 |
+--------------------------------+-------+
1 row in set (0.00 sec)
innodb_flush_log_at_trx_commit=1
表示每次事务提交都要将日志写入磁盘,这进一步加重了 IO 负担。
优化措施:
sql
-- 临时调整
mysql> SET GLOBAL innodb_flush_log_at_trx_commit=2;
Query OK, 0 rows affected (0.00 sec)
-- 验证修改结果
mysql> SHOW VARIABLES LIKE '%innodb_flush_log%';
+--------------------------------+-------+
| Variable_name | Value |
+--------------------------------+-------+
| innodb_flush_log_at_timeout | 1 |
| innodb_flush_log_at_trx_commit | 2 |
+--------------------------------+-------+
2 rows in set (0.00 sec)
-- 持久化配置
$ sudo vi /etc/mysql/my.cnf
[mysqld]
innodb_flush_log_at_trx_commit=2
-- 重启MySQL服务
$ sudo systemctl restart mysql
调整后效果:
- 磁盘 IOPS 进一步降至 5500
- 写入吞吐量提升 42%
四、其他优化建议
1. 日志文件位置调整
将 InnoDB 日志文件和 binlog 文件移动到专用 SSD 磁盘:
ruby
# 创建新的日志目录
$ sudo mkdir -p /data/mysql/logs /data/mysql/binlog
$ sudo chown -R mysql:mysql /data/mysql
# 修改my.cnf
$ sudo vi /etc/mysql/my.cnf
[mysqld]
innodb_log_file_size = 512M
innodb_log_files_in_group = 2
innodb_log_group_home_dir = /data/mysql/logs
log-bin = /data/mysql/binlog/mysql-bin
# 停止MySQL服务
$ sudo systemctl stop mysql
# 复制现有日志文件
$ sudo cp -a /var/lib/mysql/ib_logfile* /data/mysql/logs/
$ sudo cp -a /var/lib/mysql/mysql-bin.* /data/mysql/binlog/
# 修改文件权限
$ sudo chown -R mysql:mysql /data/mysql/logs
$ sudo chown -R mysql:mysql /data/mysql/binlog
# 启动MySQL服务
$ sudo systemctl start mysql
# 验证日志文件位置
$ sudo lsof -p $(pgrep mysqld) | grep -E 'ib_logfile|mysql-bin'
mysqld 12345 mysql mem REG 8,17 536870912 123456789 /data/mysql/logs/ib_logfile0
mysqld 12345 mysql mem REG 8,17 536870912 123456790 /data/mysql/logs/ib_logfile1
mysqld 12345 mysql 4u REG 8,17 12345 123456791 /data/mysql/binlog/mysql-bin.000001
2. 生产环境核心参数配置模板
ruby
[mysqld]
# 事务日志同步策略
sync_binlog = 1000 # 每1000次提交刷盘(平衡性能与可靠性)
innodb_flush_log_at_trx_commit = 2 # 每秒刷盘一次(减少redo日志IO)
# 内存与日志配置
innodb_buffer_pool_size = 8G # 缓冲池大小(建议为物理内存50-70%)
innodb_log_file_size = 512M # 单个日志文件大小(根据写入量调整)
innodb_log_files_in_group = 2 # 日志文件数量
innodb_io_capacity = 2000 # IO能力上限(SSD建议2000-5000)
innodb_write_io_threads = 16 # 异步写线程数
innodb_read_io_threads = 16 # 异步读线程数
3. 突发 IO 高负载应急响应方案
ruby
-- 突发IO高负载时临时降低同步频率
SET GLOBAL sync_binlog = 10000;
SET GLOBAL innodb_flush_log_at_trx_commit = 0;
-- 查看当前线程状态
SHOW FULL PROCESSLIST;
-- 终止长时间运行的查询
KILL 12345;
五、风险提示
sync_binlog=1000
意味着可能丢失最多 1000 个事务的 binlog 数据innodb_flush_log_at_trx_commit=2
可能导致系统崩溃时丢失 1 秒内的事务- 建议在实施前进行压测验证,确保业务可接受数据丢失风险
六、总结
MySQL 磁盘 IO 高负载是生产环境常见问题,通过合理调整sync_binlog
和innodb_flush_log_at_trx_commit
参数,结合架构优化措施,可以显著提升数据库性能。本次优化实践证明:
- 合理的参数调优可带来 60% 以上的 IO 性能提升
- 批量操作优化能有效减少日志写入次数