ionice idle类未达预期效果:CFQ调度下磁盘性能问题排查
最近在运维一台高负载Web服务器时,踩了个关于ionice和CFQ调度器的坑——本来计划用rsync迁移数据(这个操作会大量占用机械磁盘),特意用ionice -c 3把rsync进程设为idle类,想着它只会在其他程序没磁盘I/O请求的时候才干活,不会影响网站正常运行。结果系统里SSD和HDD都用CFQ调度器的情况下,磁盘还是直接被占满,网站性能急剧下降,折腾一番后整理出这些排查细节:
初始疑惑与手册查阅
查ionice手册,里面明确说idle类程序仅在其他程序未请求磁盘I/O的一段定义的宽限期后才会获得磁盘时间,对正常系统活动应该没影响。但这个「定义的宽限期」手册里根本没明确说明,网上有帖子说是fifo_expire_async的值,但没什么可靠依据。我们系统里fifo_expire_async(250ms)和fifo_expire_sync(125ms)都是默认值,按这个逻辑idle类应该几乎拿不到磁盘带宽,但实际完全不是这么回事,所以怀疑CFQ+idle的机制失效了。
验证测试过程
低I/O速率测试:确认机制失效
写了个Python程序做测试:没有加ionice的程序每秒大概30次随机读,同时开了几个不同ionice类的副本——分别是1(实时)、2(尽力)、3(idle)类,结果发现这几个进程的I/O表现完全没差异,坐实了当前环境下CFQ+idle机制根本没正常工作。
高I/O速率与异步写的关键发现
后来把I/O速率拉到每秒数百次时,发现idle类进程终于被限制了。另外还发现一个ionice手册没提的坑:异步磁盘写入完全不受I/O优先级系统控制!查ioprio_set()系统调用手册才搞明白:I/O优先级只支持读操作和同步写操作(比如用O_DIRECT、O_SYNC标记的写),异步写因为脱离了进程上下文,所以优先级控制根本不适用。
系统内核及调度器参数(sdb为HDD)
我们的系统环境信息:
Linux 4.9.0-4-amd64 #1 SMP Debian 4.9.65-3+deb9u1 (2017-12-23) x86_64 GNU/Linux /etc/debian_version = 9.3
HDD(sdb)的CFQ调度器参数:
(cd /sys/block/sdb/queue/iosched; grep . *) back_seek_max:16384 back_seek_penalty:2 fifo_expire_async:250 fifo_expire_sync:125 group_idle:8 group_idle_us:8000 low_latency:1 quantum:8 slice_async:40 slice_async_rq:2 slice_async_us:40000 slice_idle:8 slice_idle_us:8000 slice_sync:100 slice_sync_us:100000 target_latency:300 target_latency_us:300000
内容的提问来源于stack exchange,提问作者Neilski

