在Linux系统中,进程调度是操作系统的核心功能之一。想象一下CPU就像是一个忙碌的厨师,而进程就是等待烹饪的订单。调度器就是那个决定先做哪道菜的餐厅经理,它需要公平合理地分配CPU这个宝贵资源。
Linux调度器经历了多次重大演进:
注意:现代Linux系统默认使用CFS调度器,它通过红黑树数据结构管理进程队列,实现了O(log n)的时间复杂度。
Linux定义了以下几种主要调度策略:
| 调度策略 | 描述 | 典型应用场景 |
|---|---|---|
| SCHED_NORMAL | 普通分时调度策略(CFS) | 大多数用户进程 |
| SCHED_FIFO | 先进先出的实时策略 | 高优先级实时任务 |
| SCHED_RR | 时间片轮转的实时策略 | 需要公平性的实时任务 |
| SCHED_BATCH | 批处理调度策略 | 非交互式后台任务 |
| SCHED_IDLE | 极低优先级策略 | 系统空闲任务 |
优先级方面,Linux使用nice值(-20到19)和实时优先级(1-99)两个维度:
bash复制# 查看进程优先级示例
ps -eo pid,comm,ni,pri,rtprio | head -n 5
CFS的核心思想是:
计算公式:
code复制vruntime = 实际运行时间 * (NICE_0_LOAD / 进程权重)
其中进程权重由nice值决定,每差一级nice值,CPU时间权重相差约10%。
现代Linux采用模块化调度架构:
code复制stop_sched_class → dl_sched_class → rt_sched_class → fair_sched_class → idle_sched_class
调度时按照这个优先级顺序检查,每个调度类管理特定类型的进程。这种设计使得不同类型的任务(如实时进程和普通进程)能够和谐共存。
临时调整nice值:
bash复制nice -n 5 command # 以nice=5启动进程
renice 10 -p 1234 # 修改运行中进程的nice值
永久设置调度策略:
c复制// C代码设置实时优先级示例
struct sched_param param;
param.sched_priority = 80;
sched_setscheduler(pid, SCHED_FIFO, ¶m);
警告:错误设置实时优先级可能导致系统不稳定,建议保留优先级0-50给关键系统进程。
将进程绑定到特定CPU核心:
bash复制taskset -c 0,1 command # 只在CPU0和1上运行
taskset -p 0x3 1234 # 将进程1234绑定到CPU0和1
对于NUMA架构系统,还可以使用numactl工具进行更精细的控制。
关键统计文件:
实用监控命令:
bash复制# 实时查看进程调度延迟
perf sched latency
# 监控上下文切换
vmstat 1
sar -w 1
bash复制# 查看当前CFS参数
sysctl -a | grep sched
# 常用调优参数
/proc/sys/kernel/sched_min_granularity_ns # 最小调度粒度
/proc/sys/kernel/sched_wakeup_granularity_ns # 唤醒粒度
/proc/sys/kernel/sched_latency_ns # 调度周期
对于需要低延迟的应用:
bash复制# 隔离CPU核心
isolcpus=2,3 # 在内核启动参数中添加
通过cgroups v2可以更精细地控制CPU资源分配:
bash复制# 创建CPU控制组
mkdir /sys/fs/cgroup/cpu/group1
echo 100000 > /sys/fs/cgroup/cpu/group1/cpu.max
echo 1234 > /sys/fs/cgroup/cpu/group1/cgroup.procs
现象:低优先级进程长期得不到CPU时间
解决方案:
排查步骤:
mpstat -P ALL 1 查看各核利用率perf stat -e migrations 检查进程迁移次数优化方法:
场景:Nginx服务器处理混合负载(静态内容和PHP动态请求)
优化步骤:
bash复制# 示例配置
renice -n -5 -p $(pgrep -f "nginx: worker")
chrt -b -p 0 $(pgrep -f "php-fpm: pool")
taskset -c 2,3 mysqld
经过这些调整,某电商网站实现了: