Linux进程优先级与调度:nice、renice、CPU亲和性实战

同一台机器上,跑着 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)和资源限制使用,新手不要轻易碰。

七、⚠️ 常见错误

  1. 普通用户 renice -n -5 被拒 。降 nice 值需要 CAP_SYS_NICE,普通用户只能往大了调。报错 Permission denied 不是命令用错,是权限不够。
  2. 把 nice 值当成「优先级数值」 。以为数字大优先级高,结果把重要进程调成 +19,跑得更慢。记住「小数高、大数低」。
  3. 只降 CPU 优先级忘了 IO。备份任务压满磁盘 IO,应用照样卡。nice 和 ionice 要一起上。
  4. renice -n 当增量用 。把它当 nice -n 的语义,renice -n 5 以为加 5,实际是设成 5,把原本 -10 的关键进程一改就降级了。
  5. 盲目绑核。给一个多线程服务绑到单核,吞吐直接腰斩。绑核前先想清楚目的。

八、原理探究: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 管实时策略,四把工具分层下手,才能既保住线上服务质量,又让后台任务安静跑完。

相关推荐
程序员-Benothing1 小时前
Linux进程前后台管理:jobs、fg、bg、nohup、disown
linux·运维·服务器
JavaEdge.1 小时前
Docker Compose部署Dify
运维·docker·容器
企业解惑小助手2 小时前
大型企业终端如何统一管理排障实录:批量终端策略不生效问题排查
运维·服务器·网络·域智盾软件
luo_guibin2 小时前
almalinux9新系统常规命令操作
运维·服务器
进击的荆棘2 小时前
Linux系统——库的原理与制作之ELF文件的形成与加载的过程(下)
linux·动静态库
CrazyMo_2 小时前
鸿蒙高级——内存专用之linux-reserve-memory 方案简介
linux·运维·服务器
Sammyyyyy3 小时前
jev-ultrafast 实战:浏览器操作代理加本地 AI 网关,把云控制台配置做成自动化流水线
运维·人工智能·自动化·ai编程·servbay
灯澜忆梦3 小时前
【Linux】#5 | 文件与目录基础操作命令
java·linux·运维
逐梦之程3 小时前
EXCEL与DBC格式互转软件
运维·服务器·网络