先看现象。腾讯云 CVM 上 Ubuntu 22.04,ESSD 云盘做 MySQL 数据盘,scheduler 还是 mq-deadline,改成 none 之后压测 p99 从 2ms 涨到 9ms,iostat 的 aqu-sz 一直在 30 以上。

原因不止一个,得分开看。队列深度只有 32,none 不做合并排序,随机小 IO 直接把队列打满。另一种情况是云盘的 IOPS 有基线限制,换调度器动不了后端的排队。

不容易想到的是,MySQL 的 IO 线程数只有 4,并发太低,none 的顺序性优势用不上。

还有一种情况,文件系统挂载带了 sync,换调度器也躲不开同步写。

上来先确认当前调度器和队列深度

cat /sys/block/vdb/queue/scheduler /sys/block/vdb/queue/nr_requests

两种调度器下跑同一份压测

fio --name=randrw --rw=randrw --bs=4k --iodepth=32 --numjobs=4 --runtime=30 --filename=/dev/vdb --direct=1 --group_reporting

然后按队列深度切回 deadline

echo mq-deadline > /sys/block/vdb/queue/scheduler && cat /sys/block/vdb/queue/scheduler

末了确认挂载参数没有同步写

findmnt -no OPTIONS /data

我习惯把每一步的执行时间和结果记在一边,后面复盘省事。

恢复的判定其实很直接。同一份 fio 参数的 p99 回到 3ms 以内,aqu-sz 峰值降到 8 以下,MySQL 的 insert 延迟恢复正常。

补一句。单队列 NVMe 云盘用 none 合适,机械盘和深队列才需要 mq-deadline 做合并;调度器只是最后一层,IOPS 额度不够还是得换盘。这类问题最好一次改到位,反复小改反而容易把原因搅混。

作者 9823189