同一台机器上,跑着 web 服务、数据库、日志收集、定时备份。它们都想要 CPU,内核只能排队。但「谁先上、谁多分点」不是平均主义------后台备份可以慢一点,线上 API 不能卡。这一篇讲怎么用 nice、renice、ionice、taskset、chrt 去干预内核的调度决策,把宝贵的 CPU 和 IO 时间留给真正重要的进程。
一、优先级的两套体系
Linux 有两条互相独立的优先级轨道,先分清:
- 普通调度(CFS,完全公平调度) :绝大多数进程走这里,用 nice 值 衡量优先级,范围
-20 ~ +19。 - 实时调度(RT) :需要确定性响应的进程走这里,优先级
1 ~ 99,优先级永远高于普通调度。
nice 值的规则很反直觉,记住一句话就行:
nice 值越小,优先级越高,越「不客气」。
| nice 值 | 含义 | 典型用途 |
|---|---|---|
-20 |
最高优先级(最凶) | 关键系统进程 |
0 |
默认 | 普通进程 |
+19 |
最低优先级(最客气) | 后台备份、日志归档 |
所以「提高优先级」= 调小 nice 值 = renice -n -5;「降低优先级」= 调大 nice 值 = nice -n 10。
二、nice:启动时就定好脾气
语法格式
nice [-n 增量] 命令
nice 不指定 -n 时默认增加 10。
常用参数
| 参数 | 说明 |
|---|---|
-n N |
把 nice 值增加 N(默认 10) |
--adjustment=N |
同上,长选项 |
-n -N |
降低 nice 值,即提权,需 root 权限 |
示例与预期输出
把备份脚本温柔地放后台跑:
nice -n 19 tar czf backup.tar.gz /data &
预期输出:
[1] 22345
用 ps 看它的 nice 值(NI 列):
ps -o pid,ni,cmd -p 22345
PID NI CMD
22345 19 tar czf backup.tar.gz /data
给关键任务提高优先级(需要 root):
sudo nice -n -5 ./trading_engine
普通用户只能调大 nice 值(降优先级),只有 root 才能调小(升优先级)。这是内核的安全设计,防止普通进程抢占系统资源。
三、renice:给正在跑的进程改优先级
进程已经起来了想调整,用 renice。
语法格式
renice -n 新nice值 -p PID
renice -n 新nice值 -u 用户名
renice -n 新nice值 -g 进程组
注意:renice 里的 -n 是绝对目标值 ,不是增量。这一点和 nice 不同,最容易记混。
示例与预期输出
把 PID 22345 的备份进程降到底:
renice -n 19 -p 22345
预期输出:
22345 (process ID) old priority 0, new priority 19
把某用户所有进程降级(比如限制测试账号):
renice -n 10 -u tester
1000 (user ID) old priority 0, new priority 10
⚠️ nice / renice 的 -n 含义不一样
| 命令 | -n 5 的含义 |
|---|---|
nice -n 5 |
在当前基础上 加 5 |
renice -n 5 |
把 nice 值 设为 5 |
脚本里如果两个命令混用又记错含义,调出来的优先级可能完全反了。写注释,别靠记忆。
四、ionice:管磁盘 IO 的优先级
nice 只管 CPU,管不了磁盘。一个低 nice 的备份任务照样能用磁盘 IO 把整个系统的 io wait 拉满。ionice 就是来管 IO 的。
调度类别
| 类别 | 数值 | 说明 |
|---|---|---|
none |
0 | 不设置,用内核默认 |
realtime |
1 | 实时,最高优先,慎用 |
best-effort |
2 | 尽力而为,默认,配合优先级 0-7 |
idle |
3 | 只在磁盘完全空闲时才给 IO |
语法格式
ionice -c 类别 -n 优先级 命令
ionice -c 类别 -n 优先级 -p PID
示例与预期输出
让备份任务只在磁盘空闲时读写:
ionice -c 3 nice -n 19 rsync -a /data/ /backup/
-c 3(idle)+ nice -n 19,CPU 和 IO 双低,对线上几乎零影响。
给已经运行的进程调 IO 优先级:
ionice -c 2 -n 7 -p 22345
即 best-effort 类别、最低优先级 7。
合法的 nice 和 ionice 组合是「护城河」:nice 管谁多用 CPU,ionice 管谁先读磁盘,两者配合才能让后台任务真正「无感」。
五、taskset:把进程钉在指定 CPU 上
现代服务器动辄几十核,多路 CPU 还有 NUMA 差异。有时我们要把进程绑定到特定核心,减少缓存失效和跨 CPU 迁移的开销,这就是 CPU 亲和性(affinity)。
语法格式
taskset -c CPU列表 命令 # 启动时绑定
taskset -cp CPU列表 PID # 修改运行中进程
taskset -p PID # 查看当前亲和性
CPU列表 用逗号或范围表示,如 0、0,1、0-3。
示例与预期输出
让程序只跑在 0、1 两个核上:
taskset -c 0,1 ./compute_task
查看某进程跑在哪些核上:
taskset -cp 22345
预期输出(十六进制掩码 + 解析后的列表):
pid 22345's current affinity list: 0-7
pid 22345's current affinity mask: ff
把已运行进程改绑到 3 号核:
taskset -cp 3 22345
pid 22345's current affinity list: 0-7
pid 22345's new affinity list: 3
⚠️ 别乱绑核,可能适得其反
- 绑到单个核会让该核成为瓶颈,其他核闲置,整体吞吐下降。多线程程序尤其不要随便绑死。
- NUMA 场景 还要配合
numactl,把进程和内存绑到同一个 node,否则跨 node 访存更慢。 - 绑核主要用于:减少抖动 (延迟敏感)、隔离干扰 (把杂进程赶到固定核)、性能测试可复现。
六、chrt:实时调度
对延迟极其敏感的进程(工业控制、音频、高频交易),普通 CFS 保证不了确定性。可以切到实时调度策略:
# 以 SCHED_FIFO 策略、优先级 50 运行
sudo chrt -f 50 ./realtime_task
-f:SCHED_FIFO,先进先出的实时策略-r:SCHED_RR,时间片轮转的实时策略-o:SCHED_OTHER,即普通 CFS
实时进程优先级高于所有普通进程,一旦跑飞会直接饿死系统(连 SSH 都进不来)。生产上必须配合 CPU 隔离(isolcpus)和资源限制使用,新手不要轻易碰。
七、⚠️ 常见错误
- 普通用户
renice -n -5被拒 。降 nice 值需要 CAP_SYS_NICE,普通用户只能往大了调。报错Permission denied不是命令用错,是权限不够。 - 把 nice 值当成「优先级数值」 。以为数字大优先级高,结果把重要进程调成
+19,跑得更慢。记住「小数高、大数低」。 - 只降 CPU 优先级忘了 IO。备份任务压满磁盘 IO,应用照样卡。nice 和 ionice 要一起上。
renice -n当增量用 。把它当nice -n的语义,renice -n 5以为加 5,实际是设成 5,把原本 -10 的关键进程一改就降级了。- 盲目绑核。给一个多线程服务绑到单核,吞吐直接腰斩。绑核前先想清楚目的。
八、原理探究:CFS 是怎么「公平」的
现代 Linux 默认用 CFS(Completely Fair Scheduler)。它的核心思想简单到一句话:
记录每个进程累计「该得的 CPU 时间」,谁欠得最多,谁先跑。
具体实现上,CFS 给每个进程维护一个 vruntime(虚拟运行时间)。vruntime 不是真实时间,而是按权重折算后的时间:
- nice 值越高(优先级越低),权重越低,同样的真实运行时间折算出的 vruntime 增长越快。
- 调度器每次挑 vruntime 最小的进程运行------它拿到了最少的折算时间,最「吃亏」,优先补偿。
这样就自然实现了「优先级越高,分到的 CPU 越多」。nice -20 的进程权重是 nice +19 的几十倍,ronice 调一点,分到的 CPU 差距可能很大。
再理解几个常见指标与 CFS 的关系:
- load average 里的运行队列:CFS 用红黑树组织可运行进程,树节点数就是「等 CPU 的进程数」,它贡献了负载的一部分。
%Cpu(s)的wa:进程等磁盘 IO 时不占 CPU、不进运行队列(处于D状态),所以它不推高 load average 的「运行」部分(但D状态线程数会体现在 load 的另一来源)。IO 瓶颈常常 load 不高但系统很慢,就是这个原因。- 实时进程为什么能插队:RT 策略的进程不参与 CFS 的 vruntime 比较,它们有独立的、优先级更高的调度队列,所以能随时抢占普通进程。
理解 CFS 后就会明白:nice 值只是影响权重,不保证顺序,也不提供确定性。想要确定性延迟,只能上实时调度或隔离核心。
九、实战组合模板
# 1. 后台大文件压缩:CPU + IO 双低
ionice -c 3 nice -n 19 tar czf /backup/data.tar.gz /data &
# 2. 让高优先级的 API 服务少被打扰(调整已有进程)
sudo renice -n -5 -p $(pgrep -f "api_server")
# 3. 把日志采集进程赶到固定核,减少对业务核的干扰
sudo taskset -cp 7 $(pgrep -f "filebeat")
# 4. 查看某进程的 nice / 亲和性 / 调度策略
chrt -p 22345
一句话收尾:nice 管 CPU 权重、ionice 管 IO 优先级、taskset 管物理核心、chrt 管实时策略,四把工具分层下手,才能既保住线上服务质量,又让后台任务安静跑完。