qps暴跌本质是磁盘i/o排队,iostat -x 1中%util>90%、await>20ms、avgqu-sz>4同时超标即为铁证;需结合%wa、innodb_data_reads/writes突增及慢日志中using temporary/filesort现象交叉验证,并优先优化无索引排序/分组、批量无主键删改、高频大字段查询三类sql。

直接结论:QPS暴跌不是“数据库变慢了”,而是磁盘在排队等IO——iostat -x 1里%util > 90%或await > 20ms就是铁证。
确认是不是磁盘IOPS真瓶颈
别急着调参数或换硬件,先用系统命令交叉验证:
-
iostat -x 1持续观察 30 秒,重点关注%util(持续 >90%)、await(>20ms)、avgqu-sz(>4)三项同时超标 -
top看%wa(iowait)是否长期高于 30%,且 CPU 使用率不高 -
SHOW GLOBAL STATUS LIKE 'Innodb_data_reads'和Innodb_data_writes,对比历史值是否突增 3 倍以上 - 查
slow_query_log,如果大量原本 10ms 的查询突然变成 300ms+,且执行计划里出现Using temporary或Using filesort,说明 IO 被临时表/排序拖垮
优先堵住IO洪峰的三类SQL
很多 QPS 暴跌不是因为数据量大,而是某几类 SQL 在反复刷盘。重点盯:
- 含
GROUP BY或ORDER BY但字段没索引的查询:会强制生成磁盘临时表,tmp_table_size和max_heap_table_size设再大也扛不住,必须加索引或改写逻辑 - 批量
UPDATE单行、DELETE无主键条件:每行都触发 redo log + binlog + doublewrite,IO 放大效应极强;改成按主键范围分批或用INSERT ... ON DUPLICATE KEY UPDATE - 高频
SELECT *查询大文本/JSON 字段:哪怕只读 1 行,也会把整条记录(含大字段)从磁盘拉进 buffer pool,挤占缓存空间,间接导致其他查询被迫读盘
绕过磁盘的最快配置调整
这些改动不需重启 MySQL,5 分钟内生效,对 IOPS 敏感型负载见效最快:
- 降低日志刷盘频率:
SET GLOBAL innodb_flush_log_at_trx_commit = 2(注意:主机宕机可能丢 1 秒事务) - 合并 binlog 写入:
SET GLOBAL sync_binlog = 100(同样有小概率丢 binlog,但比sync_binlog = 0安全) - 放大内存缓冲:
SET GLOBAL innodb_buffer_pool_size = 50G(确保不超过物理内存 80%,否则引发 swap) - 禁用低效特性:
SET GLOBAL query_cache_type = 0(MySQL 5.7 及以下才需,8.0 已移除)
为什么SSD和RAID10不能立刻解决问题
换 SSD 或配 RAID10 是治本之策,但上线前容易忽略两个现实卡点:
- MySQL 的
innodb_io_capacity和innodb_io_capacity_max默认值(200 / 2000)是为 HDD 设计的,SSD 上必须手动调高(如设为 2000 / 4000),否则 InnoDB 主动限速 - RAID10 阵列若用 LVM 管理,且
stripesize与 InnoDB page size(16KB)不对齐,实际随机读写性能可能比单盘 SSD 还差;建议用fdisk -l /dev/sdb查对齐值,确保是 16KB 的整数倍
真正卡住 QPS 的,往往不是硬件极限,而是 MySQL 自己“不敢”用满带宽——参数没对齐,再快的盘也跑不满。











