香港服务器调度策略调优:看我我如何解决CFS在I/O密集型业务下的性能瓶颈

去年,我在香港机房维护一批承载高并发 API 和日志写入业务的服务器时,遇到了一次棘手的问题。白天业务高峰期时,用户请求延迟突然飙升,CPU 占用率却并不高。表面上负载不重,但响应时间却越来越慢,尤其在高 I/O 场景下(日志落盘、MySQL binlog、Nginx access log 同时刷写)表现尤为明显。那次排查经历,让我彻底理解了 CFS(Completely Fair Scheduler) 在 I/O 密集型业务下的调度瓶颈,并总结了一套完整的调优方法。
一、问题初现:CPU 不高但延迟升高
在香港服务器上跑的业务主要分两类:
- API 请求处理(计算轻、I/O 重)
- 日志与队列写入(典型 I/O 密集)
问题表现为:
- top 显示 CPU idle 超过 40%,系统似乎很空闲
- iostat 显示磁盘 I/O 等待 (%iowait) 最高飙到 50%
- sar -q 显示 load average 偏高,明显高于 CPU 核数
我的第一反应是磁盘瓶颈,但换成 NVMe SSD 后,问题依旧存在。这意味着问题可能出在 Linux 调度器 的策略上。
二、排查:CFS 调度器在 I/O 密集型业务下的表现
Linux 默认使用 CFS 调度器,它的设计理念是公平分配 CPU 时间片,但在 I/O 密集型业务下可能出现两大问题:
1.频繁阻塞的 I/O 线程被低估权重
I/O 线程经常阻塞在磁盘读写,CFS 会认为这些任务“不活跃”,调度权重下降
当线程重新就绪时,可能要等一段时间才拿到 CPU
2.高并发 I/O 导致调度延迟
大量短周期阻塞的线程在 CFS 队列中频繁切换
产生 sched_latency 和 wake-up latency,影响实时响应
当我用 perf sched latency 抓取调度延迟时,发现业务线程在唤醒后平均延迟达 20~30ms,远超预期。这正是 API 响应慢的罪魁祸首。
三、实操调优步骤
1. 调整 CFS 调度参数
CFS 的关键参数位于 /proc/sys/kernel/sched_*,我主要调整了以下几个:
# 查看当前参数
cat /proc/sys/kernel/sched_latency_ns
cat /proc/sys/kernel/sched_min_granularity_ns
cat /proc/sys/kernel/sched_wakeup_granularity_ns
针对 I/O 密集型业务,我做了如下优化:
# 减少调度延迟周期,让 I/O 线程更快被调度
echo 6000000 > /proc/sys/kernel/sched_latency_ns # 默认 24ms -> 6ms
echo 1500000 > /proc/sys/kernel/sched_min_granularity_ns # 默认 6ms -> 1.5ms
echo 3000000 > /proc/sys/kernel/sched_wakeup_granularity_ns # 默认 9ms -> 3ms
原理:缩短调度周期,让短生命周期的 I/O 线程更快拿到 CPU
效果:API 响应延迟降低了约 20%,高峰期稳定性明显改善
2. 对关键 I/O 线程设置 SCHED_IDLE/RT 优化
对于业务中的日志写入线程,我通过 systemd 配置 CPU affinity 与 调度优先级:
# 指定线程绑定到 NUMA Node 本地 CPU
taskset -cp 2-3 <pid>
# 提升关键 I/O 线程优先级,防止饥饿
chrt -o -p 10 <pid>
经验:不要一味提高所有线程的优先级,否则会导致 CPU 抢占严重
做法:只给核心 I/O 服务线程提升优先级,其它后台线程保持默认
3. 配合 I/O 调度器优化
CFS 负责 CPU 调度,但磁盘 I/O 调度同样重要。我把香港服务器的 NVMe 磁盘 I/O 调度器改为 mq-deadline:
# 查看当前 I/O 调度器
cat /sys/block/nvme0n1/queue/scheduler
# 切换为 mq-deadline
echo mq-deadline > /sys/block/nvme0n1/queue/scheduler
原因:mq-deadline 对低延迟和高并发随机写更友好,减少尾延迟
效果:日志写入抖动明显下降
4. 内核参数与 NUMA 调优
针对香港机房的双路 CPU 服务器,我还做了 NUMA 优化:
# 绑定进程到本地 NUMA 节点
numactl --cpunodebind=0 --membind=0 <command>
配合调度器优化,可以避免线程在跨 NUMA 节点调度时的 Cache Miss 和远程内存访问延迟。
四、调优效果与经验总结
经过这轮调优:
- 高峰期 API 响应延迟从 120ms 降到 70ms
- %iowait 从 50% 降到 15%
- Load Average 更贴近实际 CPU 使用率
我总结的经验是:
- CFS 在 I/O 密集场景下容易低估频繁阻塞线程的调度优先级
- 适度缩短调度周期、调整唤醒粒度可以显著降低延迟
- 结合 I/O 调度器和 NUMA 亲和性,能进一步释放性能
如果你在香港服务器上跑的是日志密集型、API 高并发或队列消费型业务,这套调优思路非常值得一试。