MySQL迁移后写入延迟飙升,八成是IO调度器没关——NVMe必须设none,SATA SSD得切noop或deadline;cfq在SSD上会拖慢吞吐、放大延迟抖动,需用lsblk确认设备名后执行cat /sys/block/xxx/queue/scheduler查看当前调度器,若为cfq且await持续>10ms、%util长期>95%而IOPS偏低,即证实其为瓶颈,可临时echo none > /sys/block/nvme0n1/queue/scheduler验证,再配合fio实测IOPS重设innodb_io_capacity、挂载加noatime,nobarrier、启用O_DIRECT等协同优化。

MySQL迁移后写入延迟飙升,八成是IO调度器没关——NVMe必须设none,SATA SSD得切noop或deadline,cfq在SSD上只会拖慢吞吐、放大延迟抖动。
怎么确认当前IO调度器正在拖慢MySQL
别猜,直接看设备真实配置。用lsblk先确认你的数据盘设备名(比如nvme0n1或sdb),再查调度器:
cat /sys/block/nvme0n1/queue/scheduler
输出类似 [cfq] deadline noop,中括号里就是当前生效的。如果看到cfq,尤其在NVMe或SATA SSD上,基本可以断定它在吃性能。
配合iostat -x 1观察:await持续高于10ms(SSD)、%util长期95%+,但r/s和w/s不高,说明IO请求被调度器排队卡住了,不是磁盘真忙。
临时切换调度器验证效果
不用重启,立刻生效,适合快速验证:
- 对NVMe盘:
echo none > /sys/block/nvme0n1/queue/scheduler - 对SATA SSD:
echo noop > /sys/block/sdb/queue/scheduler(或deadline) - 切完立刻跑
sysbench fileio --file-test-mode=randwrite --time=30 --threads=16 run对比IOPS和延迟变化
注意:机械盘千万别用none,它没寻道管理能力,反而会让随机IO更烂。
永久生效要改内核启动参数
临时切完有效,就得固化,否则重启就回退。改/etc/default/grub:
GRUB_CMDLINE_LINUX="elevator=none"
然后执行:
update-grub && reboot
容器或云主机环境可能受限——有些云平台(如阿里云ACK、AWS ECS)不允许改宿主机内核参数,这时得联系运维确认是否已由平台统一调优;若不可控,就只能靠MySQL层参数补救(如压低innodb_io_capacity、调innodb_flush_neighbors=0)。
为什么只换调度器还不够
调度器只是入口,后面链路不匹配照样白搭:
-
innodb_io_capacity还设着默认200?SSD下必须按实测IOPS×0.7重设(比如fio测出120K IOPS → 设90000) - 挂载选项漏了
noatime,nobarrier?云盘(ESSD/CBS Turbo)上每次INSERT多0.2ms元数据开销,积少成多 -
innodb_flush_method没设O_DIRECT?OS page cache和InnoDB buffer pool双重缓存,内存浪费且memcpy拖慢写入
最常被忽略的是:所有这些调整都得在iostat -x 1开着的前提下做,盯着await和svctm变化,而不是只看TPS数字涨没涨。


















