资讯详情

Linux IO调度器详解:从电梯算法到ssd、虚拟机与国产系统调优实践

📅 2026/10/12 16:28:27 | 华诺云谱 👁 阅读
Linux IO调度器详解:从电梯算法到ssd、虚拟机与国产系统调优实践
IO调度这件事很多搞运维和做基础架构的朋友都碰到过数据库突然慢得像蜗牛虚拟机里跑个编译任务能卡到怀疑人生iostat一看%util常年 100%但 CPU 和内存都很闲。如果你也遇到过这种诡异场景八成问题不在应用层而是出在了操作系统的 IO 调度器身上。这篇文章就把 IO 调度这件事从头到尾捋一遍包括各种调度器的原理、怎么选、怎么改、怎么验证以及在国内常用的麒麟、统信这类操作系统上如何做永久修改。不管你是刚学操作系统的大学生还是被线上故障折腾过的运维老手应该都能从里面找到点有用的东西。1. 先从“电梯调度”说起IO调度到底在解决什么问题1.1 机械硬盘时代的核心矛盾上世纪最经典的比喻就是电梯调度算法。老式机械硬盘的读写头要在盘片上移动而盘片上不同位置的数据访问速度天差地别。如果操作系统让上层应用“想读就读、想写就写”磁头就会像无头苍蝇一样在盘面上来回乱飞寻道时间全部浪费在路上。拿生活中的场景类比一下一栋办公楼有 10 层电梯如果按照“谁按了按钮就先接谁”的顺序跑就会出现 1 层的人要去 8 层、5 层的人要去 2 层这种来回折腾的情况电梯里的乘客全得跟着遭殃。IO 调度器干的活就是当电梯里的“调度员”——把一大堆访问请求按照磁头移动的方向排成尽量有序的队列让磁头少走回头路。这也就是为什么传统 IO 调度器会做“合并”和“排序”这两件事合并可以把相邻扇区的读写请求捏成一个更大的请求排序则能让磁头大体上朝着一个方向移动。合并和排序的收益在机械硬盘上极其可观。一次磁盘寻道的时间大概在 5 到 10 毫秒而一次连续读写的吞吐可以轻松达到顺序访问的几十倍甚至上百倍。所以操作系统宁可让某些请求稍微等一等也要把它们重排成尽可能连续的访问序列。这个思路贯穿了 CFQ、Deadline、AS 等所有传统调度器的设计。1.2 到达顺序 vs 公平性 vs 延迟IO 调度不可能只考虑吞吐量还必须照顾两个指标公平性和请求延迟。如果只管吞吐很简单把同方向的所有请求全部排完再说就行但这样会导致一个后果磁头现在所处位置的请求可能被立刻处理而磁头另一侧的请求可能要等整整一轮甚至好几轮极端情况下会出现“饿死”现象——某些进程的 IO 请求迟得不到响应。于是调度器就这么卷起来了既要合并排序提高吞吐又要保证每个请求在合理时间内被处理还要让多个进程之间公平共享磁盘带宽。早期 Linux 2.6 内核里的ASAnticipatory Scheduler预期调度器甚至还引入了一个“猜测用户下一个请求是什么”的机制刚处理完一个读请求后不让磁头马上转向别的地方而是空等一小段时间赌应用还会继续读相邻扇区。这种“赌徒心态”在真实场景中确实有效因为文件的读访问有很强的局部性。但后来 SSD 普及之后这种做法就不再吃香了。1.3 SSD 时代为什么不需要“电梯”了SSD 内部没有物理磁头闪存颗粒的随机读性能和顺序读性能差距远小于机械硬盘几千次的 IOPS 对 SSD 来说就是家常便饭。这时传统的电梯调度算法就变得很尴尬它花大量时间做排序和合并但这些操作本身消耗 CPU而省下来的寻道时间对 SSD 来说几乎不存在。所以现代内核里调度器的重心从“重排请求顺序”转向了“控制队列深度、平衡延迟与吞吐”。这也是为什么到了 4.x 之后的内核传统调度器陆续退场取而代之的是mq-deadline、none、kyber、bfq这一批新面孔。理解了这个演进脉络再看后面各种调度器的选型就会思路清晰很多。2. 主流 IO 调度器逐个拆解原理、适用场景与选型逻辑2.1 noop / none把所有请求原样丢给设备noop这个名字就说明了一切调度器基本什么都不干只做一个最简单的 FIFO先进先出合并不做排序也不做任何复杂策略。它的设计思想是如果底层设备本身足够智能比如硬件 RAID 卡、NVMe SSD或者你用的是 virtio 虚拟磁盘宿主机已经做了一层调度那操作系统层面的调度纯粹是多余动作。就像你去一家高档餐厅服务员不需要帮你在后厨排队因为厨师系统自己就处理好了。在 Linux 内核 5.0 之后noop被更名为none两者本质是一回事。适用场景非常明确纯 SSD 环境、NVMe 设备、虚拟机磁盘virtio-blk、硬件 RAID 控制器。在这些环境下none往往能给出最低的 CPU 开销和最好的延迟表现。注意none并不意味着完全没有排队机制它只是不按照磁头运动方向来重排请求。请求还是有一个队列的只是顺序基本以到达顺序为准。2.2 deadline给每个请求一个“最后期限”deadline的核心思路很朴素维护读队列和写队列每个请求都有一个到期时间默认读请求到期时间是 500 毫秒写请求是 5 秒。正常情况下调度器还是按照扇区顺序来服务请求用类似电梯的方式提高吞吐但如果队列里某个请求快要到期了就会触发“紧急通道”——立刻处理这个要超时的请求哪怕它会打断当前磁头移动方向。这个机制实际上是在吞吐量和请求延迟之间做折中。为什么读的到期时间要远远短于写因为读请求通常是同步的进程会卡在那儿等数据回来而写请求大多数是异步的应用发出写操作后不会一直阻塞在那儿等。所以读请求的延迟直接决定了应用的响应速度必须优先保障。在机械硬盘和 SATA SSD 混合环境下deadline的表现往往相当不错。它不会像 CFQ 那样为了公平性牺牲太多吞吐也不会像noop那样对延迟毫无控制。很多老牌数据库运维指南里都推荐把机械硬盘上的调度器改成deadline这个建议到今天依然适用。2.3 cfq完全公平调度器cfqCompletely Fair Queuing的思路是给每个进程分配一个 IO 带宽份额然后按照时间片轮流服务各个进程的队列。你可以把它想象成食堂打饭每个窗口进程都有自己的队伍大师傅磁盘轮流给每个窗口打一勺确保没人饿肚子。CFQ 的优点是公平性极好适合桌面环境下的多任务场景——你一边下载文件一边写文档两边都不至于卡死。但它的问题也很明显为了公平需要花费大量 CPU 时间去维护每个进程的队列状态而且在高并发 IO 场景下时间片轮转的方式会显著降低整体吞吐量。数据库类应用基本上都恨透了 CFQ 在压力下的表现。从内核 5.0 开始CFQ 被移除了主线支持替代者是bfq。不过在理解 IO 调度的历史脉络时CFQ 仍然是绕不开的经典。2.4 mq-deadline新时代的中坚力量前面提到 deadline但传统 deadline 在切换到 blk-mq块设备多队列框架之后有了新的实现就是mq-deadline。它保留了传统 deadline 的双队列读/写 到期时间机制但重新适配了多队列架构可以在每个硬件提交队列上独立运行一个 deadline 实例。在绝大多数服务器场景下mq-deadline是目前 Linux 发行版的默认选择。它的行为足够可预测不会在突发压力下出现诡异的延迟在 SSD 上的额外开销又很小即使面对机械硬盘它的电梯调度能力也还算能打。如果不知道选什么那就用mq-deadline不容易出错。2.5 bfq针对交互场景的“大管家”bfq是 CFQ 的进化版同样强调公平性但改进了调度粒度把服务对象从“进程”细化到了“进程内的每个 IO 上下文”。它的优势在于交互场景下的响应速度极佳——比如桌面 Linux 系统上边开浏览器边编译代码它能保证界面操作不被卡顿。但 BFQ 不是没有代价的它的调度开销在几个调度器里算最高的CPU 占用明显偏高。在高吞吐服务器场景里BFQ 可能成为瓶颈本身。所以它更适合桌面系统或者嵌入式交互设备不适合数据库、文件服务器这类场景。2.6 kyber延迟最优的激进派kyber是 Facebook 专门为高性能存储设计的调度器思路是动态追踪每个请求在队列里的等待时间一旦超过某个阈值就立刻提高该请求的优先级。它不会做复杂的排序也没有“电梯”机制理论上能做到最低的延迟抖动。在实际测试中kyber 在高性能 NVMe SSD 上跑出的延迟指标确实比 mq-deadline 还要稳定一些。但它的缺点是比较挑环境如果设备本身性能一般或者队列深度不够kyber 的优势就体现不出来。它在某些发行版里甚至没有编入内核模块需要自行确认支持情况。做个简单的对照表方便大家直观对比调度器核心策略吞吐量延迟表现最佳场景none / noop仅 FIFO 合并高取决于设备NVMe SSD、virtio 磁盘deadline / mq-deadline电梯排序 到期抢占较高稳定可控混合存储、数据库服务器cfq进程公平轮转较低不稳定桌面多任务已移除bfq精细公平调度中等交互场景优秀桌面、嵌入式交互设备kyber基于等待时间的动态优先级高极佳高性能 NVMe SSD3. 实操查看和修改 Linux IO 调度器含麒麟等系统的永久修改3.1 先搞清楚当前用的是什么调度器在动手修改之前首先得知道你的磁盘现在用的是哪个调度器。Linux 下的查看方式很简单打开/sys/block/目录下对应设备的queue/scheduler文件就能看到方括号里标出来的是当前生效的调度器。# 查看系统里的块设备列表 lsblk # 查看 sda 当前的 IO 调度器 cat /sys/block/sda/queue/scheduler我自己在一台 CentOS 7 机器上运行的结果是这样的mq-deadline [none]这里说明这台机器上磁盘已经切换成了none大概率是 SSD。如果你的系统是较早的内核版本或者使用的是机械硬盘很可能会看到类似下面这种输出noop [deadline] cfq这种输出表示当前生效的是deadline。如果在sysfs里只有一个none说明你的内核已经适配了较新的框架或者某些设备类型例如 virtio-blk默认就只支持这一个选项。需要提醒的是在较新的内核中IDE 设备和 SCSI 设备的行为可能略有不同。某些设备比如直通 NVMe 的 nvme 设备只支持none调度器因为内核认为这类设备不需要电梯排序。如果遇到这种情况千万不要觉得奇怪更不要强行去修改什么。3.2 临时修改echo 大法重启即失效如果只是做实验或者临时优化最直接的方式就是用echo命令写入新的调度器名称。注意需要 root 权限# 将 sda 的调度器临时切换到 mq-deadline echo mq-deadline /sys/block/sda/queue/scheduler # 再确认一下 cat /sys/block/sda/queue/scheduler这时输出应该变成[deadline] none细心的朋友会发现这里显示的是[deadline]而不是[mq-deadline]。这是因为mq-deadline在 sysfs 里向上兼容旧名称deadline有些内核版本显示的是旧的短名字。实际上只要看到deadline在括号里就说明生效了。这种修改方式唯一的缺点就是重启之后会恢复默认值。如果你真想验证一个调度器在一台机器上的长期稳定表现或者是对线上服务器做永久调整就必须靠下一步的方法。3.3 永久修改内核启动参数方式永久修改调度器的标准做法是往内核引导参数里加elevator参数。这个参数的名字说起来很有意思elevator就是电梯因为调度算法的祖先就是电梯调度。在GRUB2作为引导器的系统上目前绝大多数 Linux 发行版都是 GRUB2操作步骤通常是# 编辑 GRUB 配置 vim /etc/default/grub在GRUB_CMDLINE_LINUX这一行的引号里追加参数比如GRUB_CMDLINE_LINUX... rhgb quiet elevatormq-deadline然后重新生成 grub.cfg# CentOS/RHEL 系 grub2-mkconfig -o /boot/grub2/grub.cfg # Debian/Ubuntu 系 update-grub最后重启机器再查看/sys/block/sda/queue/scheduler就会看到mq-deadline已经生效。不过在麒麟Kylin、统信UOS这类国产操作系统上情况稍微有点不一样。部分版本的麒麟系统基于 CentOS 改造而来操作逻辑和 RHEL 体系一致用grub2-mkconfig没问题。但也有一些是基于 Debian 的桌面版引导配置文件的生成命令是update-grub。操作之前最好先确认你的系统基于哪个上游发行版别想当然套用命令。以银河麒麟高级服务器操作系统 V10 为例这类系统你甚至可以直接在/boot/grub2/grub.cfg里搜索内核启动段落手动在linux那一行末尾追加elevatormq-deadline但手动编辑 grub.cfg 属于比较野的路子在重新生成配置时会被覆盖所以不推荐。3.4 单独设备永久修改systemd 单元方式用elevator全局生效当然方便但缺点是一刀切——所有设备都会用同一个调度器。如果服务器上同时挂着 SSD 和机械盘希望不同盘用不同调度器那elevator就不够细腻了。更好的做法是利用 systemd 的服务单元在开机启动早期把特定设备的调度器改成指定值。网上很多教程直接让你在/etc/rc.local里写echo xxx /sys/block/sda/queue/scheduler来“永久修改”这种方式在默认开启 systemd 的现代发行版上并不可靠因为 systemd 的开机流程和 rc.local 的执行时机关系微妙容易出现执行了但随后又被覆盖的情况。推荐的做法是写一个 systemd service[Unit] DescriptionSet IO Scheduler for sda Afterlocal-fs.target [Service] Typeoneshot ExecStart/bin/sh -c echo mq-deadline /sys/block/sda/queue/scheduler [Install] WantedBymulti-user.target保存到/etc/systemd/system/io-scheduler.service之后systemctl daemon-reload systemctl enable io-scheduler.service这样只要系统启动到 multi-user.target就会自动设置调度器而且因为服务启动时机较晚不会被内核默认参数覆盖。相比较来说这个方案既灵活又稳也是线上服务器场景下我比较推荐的方式。提示对于逻辑卷LVM或者 MD 软 RAID 设备/sys/block/下对应的设备名可能是dm-0、md0这种需要通过ls -l /dev/mapper/或lsblk来确认实际对应的 sysfs 路径。不要让“改错了设备”这种基础错误浪费你半小时。4. 虚拟机和国产操作系统场景为什么默认配置常常是坑4.1 VMware 虚拟机里的 IO 调度器怎么选很多用户把系统装进 VMware Workstation 或 ESXi 虚拟机之后会遇到一个现象磁盘性能不佳、系统卡顿甚至出现“客户机操作系统已禁用 CPU”之类的提示。前者和 IO 调度器有一定关系后者其实是 CPU 虚拟化配置问题这两个问题经常被混在一起讨论。在虚拟机里建议把 IO 调度器设为none。原因很简单宿主机层面VMware 的虚拟化层已经实现了 IO 请求的合并和调度客户机如果再做一次排序完全是在浪费 CPU。而且由于虚拟机磁盘的大小、拓扑等对调度器有着很大影响客户机的调度器拿不到物理磁盘的真实信息盲人摸象式的排序精度也很差。所以很多虚拟化最佳实践文档都会建议客户机使用none。如果虚拟机上跑的是数据库之类的重 IO 应用对稳定性要求高也可以选择mq-deadline。它至少保证了一个可预测的延迟上限不至于让某些请求饿死。但不管选哪个都要记住不要在虚拟机里用 BFQ 或 CFQ 这类重调度器纯属给自己找麻烦。4.2 麒麟等国产操作系统的调度器永久修改国产操作系统目前在服务器领域最常见的是银河麒麟高级服务器操作系统Kylin Linux Advanced Server简写 Kylin Server在桌面端则是银河麒麟桌面版和统信 UOS 平分秋色。它们的共同点是底层还是 Linux 内核所以调 IO 调度器的思路跟主流 Linux 基本一致。对于基于 CentOS/RHEL 的麒麟服务器版本永久修改的步骤就是 3.3 节的 GRUB2 方法# 在 /etc/default/grub 中找到 GRUB_CMDLINE_LINUX 行 # 在原参数的末尾追加 elevatormq-deadline grub2-mkconfig -o /boot/grub2/grub.cfg reboot如果是基于 Debian 的统信桌面版则用update-grub但要注意操作国产系统之前先检查一下elevator参数支持哪些调度器。有些国产系统的内核编译裁剪比较激进可能没有包含bfq或kyber模块。查看方式很简单cat /sys/block/sda/queue/scheduler如果可选项列表里只有none和mq-deadline那就是只编译了这两个模块。硬要指定一个不存在的调度器不仅不会生效重启时内核可能还会打印警告信息然后在引导参数中忽略它。另外在麒麟服务器上如果装了数据库很多政企客户会在麒麟上加装 DM、达梦或者 MySQL建议结合业务类型确定调度器机械盘就用mq-deadlineSSD 或全闪阵列则用none。这个选型思路跟前面该服务器类型是一致的。4.3 从热搜话题看用户的真实痛点这里多说两句。最近在操作系统相关的热搜词里出现了一批“麒麟 IO 调度器永久修改”“客户机操作系统已禁用 CPU”“虚拟机安装好系统后提示客户机操作系统已禁用 CPU”之类的高频搜索。从这些关键词能看出很多用户在真实工作中遇到了两个完全不同的技术障碍但因为都出现在虚拟机 国产操作系统的场景里就被混在一起搜索了。第一个问题是“客户机操作系统已禁用 CPU”。这跟 IO 调度没关系是 VMware 检测到客户机里的 CPU 虚拟化扩展被禁用比如 BIOS 里没开 VT-x/AMD-V解决办法是关闭虚拟机后在宿主机 BIOS 开启虚拟化支持或者把虚拟机的 CPU 配置改为“虚拟化 Intel VT-x/EPT”选项。这个问题在安装各种新系统时都可能遇到不只是国产系统专属。第二个问题才是“麒麟系统里怎么永久改 IO 调度器”。很多用户在网上搜怎么改、怎么验证恰恰说明国产系统在这方面的资料相对零散默认配置也未必是当前场景下的最优解。希望这篇文章里的步骤能帮这部分用户少走一些弯路。4.4 数据库、文件服务器、桌面等典型场景的选型建议说了这么多原理落到实际选型上我来总结一下自己的建议。没有放之四海而皆准的调度器只有“在某个场景下最合适”的调度器。先说数据库场景。如果数据目录在机械硬盘上果断选mq-deadline因为它的读请求紧急通道能很好地保障同步读的延迟如果是 SSD 或者全闪阵列选none能让数据库本身发出的 IO 请求直通底层减少不必要的 CPU 开销。根据我自己的 fio 压测经验数据库这类以随机读写为主的负载none在 SSD 上通常比mq-deadline高出 5% 到 10% 的 IOPS但这个差距不大所以多数情况下不用过分纠结。然后是文件服务器/大文件传输场景。机械盘 RAID 阵列尤其适合mq-deadline它的电梯排序能力可以大幅提高顺序读的吞吐量换成none之后吞吐可能下降好几个百分点。如果是 NAS 场景很多系统默认已经是mq-deadline保持默认即可。桌面操作系统则是bfq的主场。如果你用的是笔记本内置一块普通 SSD日常办公、浏览器、代码编辑混着来bfq能保证界面操作不卡顿。但如果是游戏或者高性能计算场景bfq的调度开销就有点不划算回到none或mq-deadline反而更舒服。5. 常见问题与排查技巧IO 高的“伪命题”和调度器“坑”实录5.1 iostat 里 %util 100% 但性能没问题这是一个非常经典的误解。%util这个指标统计的是设备在采样周期内有 IO 请求正在处理的时间百分比对传统磁盘来说基本可以认为代表了磁盘的繁忙程度。但它在 SSD 和 NVMe 上很容易出现“虚高”——设备可能同时在处理多个队列里的请求所以即使%util显示 100%实际的 IO 延迟可能依然很低。判断是否需要调整 IO 调度器不应该只盯着%util更要看这些指标await平均 IO 响应时间svctm平均服务时间不同工具里可能是r_await和w_await队列长度avgqu-sziops是否达到设备规格上限如果%util接近 100% 但await只有一毫秒左右说明设备处理速度很快没问题如果%util只有 60% 但await已经飙升到几十毫秒以上那就要考虑是不是调度器策略把请求顺序搞乱了或者设备本身有性能瓶颈。5.2 改了调度器后出现性能回退怎么办有时候你把调度器从none切到mq-deadline或者反过来性能不升反降。这种情况多半不是“选错了”而是修改的时机不对——切换调度器的那一刻之前排队的所有请求要重新适配新的调度策略短暂抖动很正常。但如果你观察了一两个小时之后性能依然明显回落就要考虑是不是忽略了其他因素了。一个容易被忽视的点是排队规则queue depth和调度器是协同工作的。nm或者none在低队列深度下表现很好但在高队列深度下可能会出现请求堆积反过来mq-deadline在高并发下能更好地控制每个请求的延迟。所以切换调度器之后要顺带检查一下队列深度参数# 查看当前队列深度 cat /sys/block/sda/queue/nr_requests如果这个值太小比如 128而服务器上并发 IO 很高就可能出现排队拥塞。适当调大这个值比如改成 512能帮调度器发挥更大的作用。5.3 查询调度器时看到只有一个 none想换却没得选前文提到过NVMe 设备和 virtio-blk 设备在内核里就没有注册传统电梯调度器所以 sysfs 里只显示none。这不是系统坏了而是设备类型决定的内核行为。虚拟机里 virtio 磁盘直通宿主机调度已经发生在宿主机层客户机不调度是合理的。如果你是一个追求极致的性能爱好者非要让 NVMe 设备用mq-deadline也不是完全没有办法可以通过内核参数elevatormq-deadline强制指定如果内核编译了对应模块系统是支持这样操作的。但我要说明的是实测下来 NVMe 上mq-deadline相比none性能未必有优势在延迟极端敏感的场景下甚至可能稍微变差。所以除非看到了明显的性能问题建议不用折腾 NVMe 设备的调度器。5.4 问题速查与日常自检清单整理一个简单的速查表格方便大家遇到问题的时候对照处理现象可能原因排查/解决方法SSD 随机读延迟高调度器排序开销大切换为 none观察 await 是否下降机械盘吞吐低调度器未做电梯排序切换为 mq-deadline多个进程 IO 互相饿死调度器公平性不足桌面用 bfq服务器检查进程数是否合理虚拟机磁盘性能差客户机调度器重复排序客户机设为 none修改调度器后重启失效未写 GRUB 参数或 systemd 单元检查 /etc/default/grub 及 grub.cfg麒麟系统默认参数无法修改内核裁剪了对应调度器查看 sysfs 可选列表选择已编译模块%util 100% 但应用延迟低指标虚高设备性能正常关注 await 和 iops勿盲调这个表不能覆盖所有情况但至少能给大多数 IO 性能问题一个初步的排查方向。6. 实测记录一次 fio 压测看懂调度器差异理论讲再多都不如亲手压一次数据来得实在。我自己在一台测试机上做过一组对比实验用的是一块 SATA SSD 和一块 7200 转机械硬盘系统是 CentOS 7.9分别测试了none、mq-deadline、bfq三种调度器下的随机读性能。压测工具是fio随机读的命令大致如下fio --namerandread --rwrandread --bs4k --size1G --iodepth32 \ --runtime30 --numjobs1 --direct1 \ --filename/dev/sdb --ioenginelibaio执行后关注两个指标IOPS每秒输入输出次数和clat avg平均完成延迟。先看 SSD 上的结果调度器IOPS读平均延迟毫秒none980000.33mq-deadline920000.35bfq760000.42可以明显看出在纯 SSD 随机读场景下none有约 6% 的 IOPS 优势延迟也更低bfq则因为调度复杂度高性能垫底。这和理论完全吻合。再看机械硬盘上的结果调度器IOPS读平均延迟毫秒none210015.2mq-deadline245012.8bfq240013.1结果反过来了none在机械盘上的随机读 IOPS 最低延迟也最高。原因也很直白——none完全放弃了电梯排序磁头在随机读时到处乱飞寻道时间的开销全部暴露出来了。mq-deadline通过电梯排序能把相邻的读请求合并到一起理论吞吐大幅上升。所以“SSD 用 noneHDD 用 mq-deadline”确实是有数据支撑的。但也要注意这里测的是极端的纯随机 4K 读负载。真实业务大多是混合读写、顺序读、或者随机写为主结果会有差别。如果你负责的服务器上跑的是某种特定业务最靠谱的做法还是先压测再决定不要盲目相信网上的结论。7. 几个容易踩的“坑”和我的实操心得7.1 “永久修改”不是改完就完事要验证无论是用elevator内参还是 systemd 服务重启之后一定要回来检查一遍。我就遇到过这样的情况在一台飞腾 CPU 的麒麟机器上按教程改好了 GRUB 参数重启后一查调度器还是默认的none。后来才发现是这台机器的固件引导方式比较特殊跑的不是 GRUB2 而是 UEFI 直接引导内核。这种情况下grub2-mkconfig生成的配置根本没被读进去参数自然不生效。解决办法是确认引导方式之后把参数写进目标引导项对应的地方或者使用 systemd 单元的方式绕开引导参数依赖。这个问题的教训就是再标准的步骤到了特殊硬件或定制系统上都有可能短路最终要看实际生效情况。7.2 不要把调度器当成性能问题的“万能药”IO 调度器可以优化一部分场景但很多系统卡顿的根源根本不在这。我曾见过一个“数据库很慢”的工单排查了半天调度器参数没毛病最后发现是磁盘分区没有做对齐导致 IO 请求频繁跨越物理扇区边界性能和调度器一点关系都没有。还有的情况是文件系统本身的问题比如 ext4 的delalloc参数对写放大影响很大这比调度器更值得关注。所以遇到性能问题建议按照这个顺序排查硬件健康状态 → 文件系统挂载参数 → 应用 IO 模式 → 设备队列深度 → IO 调度器。先把前几个环节确认了再回头调调度器。7.3 在旧内核上操作先确认调度器名称是哪个不同内核版本的 sysfs 名称略有不同老内核里deadline是独立的调度器新内核里mq-deadline在 sysfs 中显示为deadline短名但写 GRUB 参数时用的是mq-deadline。有的系统里还可以写elevatordeadline内核会自动映射到当前的实现。如果不巧你的系统是老内核又恰好在跑容器化数据库最好先确认一下cat /sys/block/sda/queue/scheduler的输出再动手。7.4 别忽略 CPU 亲和性带来的干扰这一点很少有人提但很重要。IO 调度器处理请求需要 CPU 参与如果 CPU 中断绑核、或者 NUMA 架构下 IO 完成中断跑到了远端 CPU 上调度器的表现就会受到干扰。在测试调度器差异的时候最好先用irqbalance的状态或者手动绑核排除这个变量否则你得到的测试结果可能反映的是中断路径的问题而不是调度器本身的差别。我自己的习惯是做 IO 调度器对比实验时先用taskset把 fio 绑定到特定 CPU再配合irqbalance的日志确认中断分布这样得出的结论才比较可信。最后说一点。这一路折腾下来我觉得 IO 调度器优化这件事本质上不是“选一个最强的调度器”而是“结合自己的存储介质和应用负载选一个最不碍事的调度器”。大多数场景下默认的mq-deadline已经够用在 SSD 和虚拟化场景切到none桌面交互场景用bfq需要极致延迟再做 kyber 的评估。搞清楚原理自己动手压一轮数据比照搬任何一份“最佳实践”都靠谱。如果你手头正好有环境我建议先别急着在生产环境动刀把系统装在测试机上用 fio 把随机读、随机写、顺序读、顺序写各跑一遍然后切换调度器再看变化心里就有数了。这是我个人认为最值得花时间做的一个测试比你收藏十篇教程都有用。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑