同一台机器上跑着 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--adjustmentN同上长选项-n -N降低 nice 值即提权需 root 权限示例与预期输出把备份脚本温柔地放后台跑nice -n 19 tar czf backup.tar.gz /data 预期输出[1] 22345用ps看它的 nice 值NI 列ps -o pid,ni,cmd -p 22345PID NI CMD 22345 19 tar czf backup.tar.gz /data给关键任务提高优先级需要 rootsudo 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 tester1000 (user ID) old priority 0, new priority 10⚠️ nice / renice 的-n含义不一样命令-n 5的含义nice -n 5在当前基础上加 5renice -n 5把 nice 值设为 5脚本里如果两个命令混用又记错含义调出来的优先级可能完全反了。写注释别靠记忆。四、ionice管磁盘 IO 的优先级nice 只管 CPU管不了磁盘。一个低 nice 的备份任务照样能用磁盘 IO 把整个系统的 io wait 拉满。ionice就是来管 IO 的。调度类别类别数值说明none0不设置用内核默认realtime1实时最高优先慎用best-effort2尽力而为默认配合优先级 0-7idle3只在磁盘完全空闲时才给 IO语法格式ionice -c 类别 -n 优先级 命令 ionice -c 类别 -n 优先级 -p PID示例与预期输出让备份任务只在磁盘空闲时读写ionice -c 3 nice -n 19 rsync -a /data/ /backup/-c 3idlenice -n 19CPU 和 IO 双低对线上几乎零影响。给已经运行的进程调 IO 优先级ionice -c 2 -n 7 -p 22345即 best-effort 类别、最低优先级 7。合法的 nice 和 ionice 组合是「护城河」nice 管谁多用 CPUionice 管谁先读磁盘两者配合才能让后台任务真正「无感」。五、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 22345s current affinity list: 0-7 pid 22345s current affinity mask: ff把已运行进程改绑到 3 号核taskset -cp 3 22345pid 22345s current affinity list: 0-7 pid 22345s new affinity list: 3⚠️ 别乱绑核可能适得其反绑到单个核会让该核成为瓶颈其他核闲置整体吞吐下降。多线程程序尤其不要随便绑死。NUMA 场景还要配合numactl把进程和内存绑到同一个 node否则跨 node 访存更慢。绑核主要用于减少抖动延迟敏感、隔离干扰把杂进程赶到固定核、性能测试可复现。六、chrt实时调度对延迟极其敏感的进程工业控制、音频、高频交易普通 CFS 保证不了确定性。可以切到实时调度策略# 以 SCHED_FIFO 策略、优先级 50 运行 sudo chrt -f 50 ./realtime_task-fSCHED_FIFO先进先出的实时策略-rSCHED_RR时间片轮转的实时策略-oSCHED_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 默认用CFSCompletely 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 管实时策略四把工具分层下手才能既保住线上服务质量又让后台任务安静跑完。