cat /sys/block/设备名/queue/scheduler是唯一可靠方式,需逐设备查询,输出中方括号内为当前生效项;NVMe设备显示[none]属正常绕过软件调度。

cat /sys/block/设备名/queue/scheduler 是唯一可靠方式
Linux 没有全局“当前 IO 调度算法”这个概念,每个块设备(如 sda、nvme0n1)独立维护自己的调度器,必须逐个查。其他命令如 lsblk -D、df、cat /proc/partitions 都不暴露调度器信息——它们只管容量、分区或挂载状态,和调度策略无关。
正确流程是:
- 先用
lsblk -d列出物理块设备,排除loop、zram、dm-等逻辑设备 - 对目标设备(比如
sda或nvme0n1),执行cat /sys/block/sda/queue/scheduler - 输出形如
noop [mq-deadline] kyber bfq none,方括号内即当前生效项
看到 [none] 别慌,尤其 NVMe 设备这是正常行为
[none] 在 nvme0n1 上不是配置错误,而是内核主动绕过软件调度层,把请求直接交给硬件队列处理。这是 5.0+ 内核对 NVMe 的默认优化策略。
常见误操作:
- 对
nvme0n1执行echo kyber > /sys/block/nvme0n1/queue/scheduler→ 报Invalid argument或静默失败 - 在阿里云 ESSD、AWS io2 等云盘上尝试修改 →
/sys/block/vda/queue/scheduler可能根本不存在,或只读 - 把
[none]当成 bug,反复重试写入 → 浪费时间,且可能掩盖真实问题(比如驱动未加载)
临时切换后必须回读验证,不能只信 echo 没报错
echo deadline > /sys/block/sda/queue/scheduler 成功返回不代表真的生效。尤其在 RAID 卡、老旧驱动或混用介质的机器上,写入可能被内核忽略。
确认是否生效的唯一办法:
- 写完立刻再跑一次
cat /sys/block/sda/queue/scheduler,看方括号是否移到目标项上 - 对根设备(如装系统的
sda),建议随后用iostat -x 1观察 30 秒,检查await和%util是否出现异常抖动 - 若反复写入仍卡在原值,说明该设备不支持目标调度器,或内核未编译对应模块(如
bfq需要CONFIG_BLK_MQ_BFQ_MODULE=y)
永久修改得靠 GRUB 参数,不是改配置文件或写脚本
运行时修改重启就丢,真正要持久化,必须通过内核启动参数 elevator=xxx 实现。这不是 systemd 服务、也不是 udev 规则能覆盖的层级。
操作要点:
- 编辑
/etc/default/grub,在GRUB_CMDLINE_LINUX_DEFAULT行末加空格分隔的elevator=mq-deadline - 执行
sudo update-grub(Debian/Ubuntu)或sudo grub2-mkconfig -o /boot/grub2/grub.cfg(RHEL/CentOS) - 注意:该参数对所有块设备统一生效,无法为 SSD 和 HDD 分别指定;若系统混用介质,更推荐用 udev 规则按设备名精准控制
最易被忽略的一点:调度器选择必须匹配设备类型和内核版本。比如在 5.0+ 内核下对 SATA SSD 强行用 cfq,或对 NVMe 硬写 noop,不仅无效,还可能干扰固件原生队列管理。


















