首页 / 资讯中心 / 文章详情

Linux renice命令实战:调整运行中进程优先级,解决CPU占用过高

Linux renice命令实战:调整运行中进程优先级,解决CPU占用过高 ★ FEATURED ARTICLE
你是不是也遇到过这种情况后台跑着某个统计任务CPU一下就被打满结果整台服务器的响应速度肉眼可见地变慢明明登录上去只是想查个日志却要等好几秒才能敲进去命令。这时候如果不想重启机器、也不想把任务直接 kill 掉重来最常见的手法就是动一下进程的调度优先级——在 Linux 系统管理里干这件事的命令老牌、稳定、一行生效它就是 renice。renice 的核心作用很简单修改一个已经在运行的进程的 nice 值也就是调度优先级。它和启动时用的 nice 命令正好互补nice 管开始renice 管中途。这篇实操篇会从底层原理讲到完整场景从命令语法讲到权限限制和常见坑内容主要面向正在系统学习 Linux 常用命令的运维新手也适合那些背了命令但不知道什么时候该用、怎么用得体的朋友。1. 优先级是怎么决定的nice 值背后的调度逻辑1.1 nice 值到底是什么在看 renice 的语法之前得先搞明白我们改的那个数字到底在系统里起什么作用。Linux 内核管理着几十上百个进程CPU 资源是有限且排队的谁先跑、谁后跑、谁多跑一会儿由调度器来决定。调度器做这个决定时除了进程状态和负载情况还会读一个优先级参数这个参数在 Linux 上有一个非常接地气的名字叫 nice value翻译过来就是“谦让值”。数字范围从 -20 到 19默认是 0。数值越小优先级越高越“不谦让”数值越大优先级越低越“好说话”。打个比方就好比早高峰坐公交-20 的进程是那种一看到车来就直接插队上车的人19 的进程则是站在门口举着“你们先走我等下一班”牌子的人。之所以叫 nice是因为你越愿意把 CPU 资源让给别人数字就越大越“乖”。在 Linux 主流的 CFS 调度器完全公平调度器里nice 值并不是简单地把时间片乘以几倍而是转换成进程的权重值。权重高系统在有竞争时就会多分时间片权重低自然少分一些。说得再直白些单个 nice 值的变化对单核 CPU 上的单进程影响有限但当服务器上有几十、上百个进程都在抢 CPU 时这个权重就会明显影响每个人的执行速度和工作体验。1.2 renice 与 nice 的分工差异很多人分不清 nice 和 renice其实它们的核心机制一样区别只在于介入时间点。nice 命令是在你要启动一个程序时给新进程预设 nice 值例如nice -n 10 ./backup.sh这条指令会以 10 的 nice 值启动 backup.sh。它影响的是“还没出生”的进程。而 renice 恰好反过来它针对的是已经跑起来的进程不用重启、不用重来只要拿到 PID就能现场调整例如renice -n 10 -p 12345。这两个命令在运维日常里常常搭配使用。预判到某个任务会占资源就在启动时用 nice 设好初值任务跑起来才发现占资源就临时用 renice 补救。还有一个值得注意的细节在 Linux 里新建的子进程通常会继承父进程当前的 nice 值。换句话说如果你在父进程上改了 nice它后续 fork 出来的新子进程也会沿用新值但已经存在的旧子进程不会自动跟着变——这个坑后面我会专门讲。2. 命令格式速记与查看状态的方法2.1 renice 参数速查老规矩先看最常用的参数形式renice -n 新的nice值 -p 进程PID renice -n 新的nice值 -u 用户名 renice -n 新的nice值 -g 进程组ID其中-p指定 PID-u指定用户名或 UID-g指定进程组 ID。-n后面的值就是要设置的目标 nice 值范围是 -20 到 19。需要说明的是renice 的老版本语法也可以直接写成renice 10 -p 12345不带-n前面的位置新版本依然兼容但我建议始终带上-n可读性更好脚本里也更不容易出错。针对不同目标的调整我整理成一张表方便查阅目标命令示例说明单个进程renice -n 5 -p 12345设置 PID 为 12345 的进程多个进程renice -n 5 -p 12345 12346 12347-p后面可以跟多个 PID某个用户的所有进程renice -n 10 -u www-data批量调整该用户下的所有进程某个进程组renice -n 10 -g 5001按 PGID 调整整组任务配合查找命令renice -n 19 -p $(pgrep -f backup_script)先定位再调整命令行小白最容易忽略的一点是renice 一次设置的是“绝对值”不是“相对增量”。renice -n 5是把 nice 设成 5不是“在原来基础上加 5”。如果你希望相对调整需要自己先查当前值再算出目标值。有些教辅材料会说 renice 支持直接renice -n 5 -p PID的写法但不同的 init 系统和发行版处理方式并不一致我实际测试时发现有些环境并不支持、还容易报语法错误所以更稳妥的做法是显式写出最终目标值。2.2 调整前先看清当前状态不掌握现状就去调参数等于闭着眼睛配网络出了问题根本不知道是谁的锅。所以动手之前先用以下方法确认进程当前的位置。最简单的就是ps工具。查看单一进程ps -o pid,ppid,user,nice,pri,cmd -p 12345输出里nice列就是进程当前的 nice 值pri是内核显示的动态优先级。如果你想把整机进程按 nice 值从小到大排看看哪些进程目前在“插队”抢资源可以直接ps -eo pid,user,nice,cmd --sortnicetop 里也能看。进入 top 后默认界面的NI列就是 nice 值。如果没看到这一列按f进入字段管理找到 NI 字段并选中显示。top 中还有一个很方便的交互操作按r键输入进程 PID再输入新 nice 值它会自动帮你执行 renice。虽然本质是同一个命令但对不熟悉命令行参数的人来说这个交互模式非常友好。htop 也是类似直接选中进程按 F7 降低优先级、F8 提高优先级可视化程度更高适合临时快速调整。我看过的很多教材都喜欢让人直接记“NI 是 nice 值”这句话没错但有个细节要提醒一下top 的第一行PR列显示的是动态优先级不是 nice 值本身。普通进程的 PR 通常由 nice 值倒推计算出来但忽略它、只看 NI 列更不容易受版本差异干扰。尤其是在某些发行版里PR 列在不同内核版本下的算法有差异纠结它意义不大排查问题先盯 NI 列就好。3. 实战场景什么情况用 renice、怎么用3.1 后台编译任务太占 CPU给任务“让位”这是我日常碰到最多的场景。比如运维同学直接在服务器上编译源码或者管理员跑了make -j8CPU 瞬间飙到满载。这种编译任务通常不是关键业务但它的存在会让 Web 服务、数据库等核心进程变得发疯慢。先用ps找到编译进程ps -eo pid,user,nice,cmd | grep make假设输出显示 make 的 PID 是 29217当前 nice 值为 0我一般直接压到 15 左右renice -n 15 -p 29217x的优点就在这里命令执行完立刻生效不用让正在跑的编译停下来重来。但注意一点如果编译任务已经派生出大量子进程而且这些子进程是之前就存在的你只调整父进程旧子进程不会自动跟随新值。更稳妥的做法是找到这个编译任务的进程组整组一起调。进程组 ID 可以这样查ps -o pid,pgid,cmd -p 29217假设 PGID 是 29217那直接renice -n 15 -g 29217这样整条任务链路上的旧进程新进程都会统一降到低优先级。如果是已经意识到任务会占资源更好的做法是启动时直接用 nice 设置nice -n 15 make -j8 虽然启动前设好值能省去后面再调组的麻烦但很多实际场景根本来不及预判所以 renice 的价值在于“事后补救”。3.2 核心业务响应慢尝试给关键进程提优先级反过来也有场景。比如你发现一个数据库进程、中间件进程或某个实时处理程序响应特别慢其他负载又不算特别高这时候可以考虑把它的 nice 值降低让它抢到更多 CPU 时间。假设某个 Redis 实例的 PID 是 37001当前 nice 是 0renice -n -5 -p 37001这里要着重提醒给核心业务设置负 nice 务必克制。-5 通常是起点不要一上来就 -15、-20。因为负的 nice 值会让进程在 CPU 竞争时处于绝对优势一旦它本身有性能问题反而可能把整台机器拖垮直接造成其他进程饿死。我在生产环境里见过有人把一个异常任务的优先级拉到 -19结果 CPU 几乎全被它一个人吃光最后不得不重启机器才恢复。所以这里的建议是先做小步调整观察 5 到 10 分钟确认没有副作用再做下一步。顺便说一句如果某进程本来就因为锁等待、I/O 阻塞或网络问题导致慢你把它 nice 调得再低也没用。CPU 优先级只能缓解 CPU 竞争导致的延迟解决不了磁盘 I/O 和网络瓶颈带来的卡顿。判断是不是 CPU 问题最简单的办法是在 top 里看该进程 CPU 占用率是不是接近 100%如果是renice 才可能有效。3.3 批量调整某个用户的所有进程运维时另一个高频场景是某个服务账号或业务账号运行了大量任务它们集体把系统资源占满了。一个个调整 PID 又笨又不现实这时候直接用-u处理。renice -n 10 -u deploy这条命令会把 deploy 用户当前所有进程的 nice 值统一设置为 10。它适合解决“某个账号下的某个批量任务失控”的场景但要小心如果该用户同时运行着重要的常驻服务批量降低优先级会影响所有进程。所以下达这个命令前最好用下面的指令先看看这个用户到底占了多少资源ps -u deploy -o pid,user,nice,cmd --sortnice看清再动手。批量操作虽然方便但副作用也大我通常只在“宁可慢、不可死”的任务型账号上使用比如跑批、爬虫、离线程式极少对关联重要业务的多用途账号做全局调节。3.4 一行命令的组合技日常 Shell 操作中renice 经常和 pgrep、ps、pgid 组合使用形成一行流renice -n 19 -p $(pgrep -f backup_script)这表示找到命令行中包含 backup_script 的进程然后把它们的 nice 值设为 19。要注意的是如果 pgrep 匹配出多个 PID这条命令会同时调整多个进程-p参数天然支持多 PID。还有一个小细节如果 pgrep 匹配到了你自己所在的当前 Shell 进程小心把自己当前的交互终端也调成低优先级第一次手滑时整个终端卡到怀疑人生。所以匹配条件尽量具体比如把backup_script写完整别用一个过短的关键词。4. 实操中的五个关键注意点4.1 权限边界不是所有值你都能设renice 最容易被忽略的坑就是权限问题。root 用户可以把任意进程的 nice 值调整为 -20 到 19 之间的任意值没有任何限制。普通用户则有两个明显的限制第一只能调整属于自己的进程动不了别人的进程第二只能增加 nice 值——也就是降低优先级——不能把 nice 调成负数来提高优先级。比如你用普通用户执行renice -n 5 -p 12345如果这个进程是你自己的成功。但如果换成renice -n -5 -p 12345通常你会看到Operation not permitted或者Permission denied的报错。这是内核刻意设计的安全边界防止低权限用户通过调整优先级抢占系统资源、影响别人。这个限制还有一个延伸知识点即使你是 root如果在容器或某些受限的虚拟化环境中运行即使 uid 是 0也不一定能修改进程优先级。因为容器默认可能没给 capabilityCAP_SYS_NICE。这种情况下命令会直接报错你需要检查运行环境的能力集配置而不是怀疑命令写错了。4.2 子进程不会自动跟随旧进程调整前面已经提过一次这里再展开。Linux 的 fork 机制决定了子进程在 fork 的那一瞬间会继承父进程的 nice 值fork 完成后你再改父进程的 nice已经存在的子进程不会自动变只有父亲后续创建的新子进程会继承新值。这句话翻译成人话就是你对一个已经跑了一会的父进程执行 renice它下面的旧子进程依然保持原来的优先级新子进程才会用新的 nice 值。如果这个父进程是那种一次性 fork 了大量子进程、然后自己慢慢等待的管理进程只调父进程几乎等于没调。解决办法有两个要么用进程组整体调执行renice -n 值 -g PGID要么递归调整。递归的做法是用 pstree 看进程关系再对每个子孙 PID 执行 renice虽然麻烦但适合那种进程组关系混乱、不能简单按组处理的场景。4.3 CPU 没打满时调整了也感觉不到变化很多人第一次用 renice 都抱着“改完立刻快如闪电”的期待结果发现什么都没变。这不是命令失效了而是系统此时根本不缺 CPU。nice 值只在 CPU 成为瓶颈时有意义。当系统 CPU 还有大量空闲时调度器本来就能满足所有进程优先级调高调低都不会对执行速度产生明显差别。所以在调整之前先用top或mpstat看一眼整体负载如果 load average 不高、CPU 空闲率还很高就别指望 renice 能带来多大体感变化。遇到这种情况优先去查 I/O 和内存瓶颈而不是继续折腾优先级。4.4 不要在关键服务上盲目使用负优级这是我最想强调的一点。负 nice 值是把双刃剑它能给关键进程争夺 CPU同时也可能把系统的公平性破坏掉。一个长期以 -20 优先级运行的常驻服务一旦进入异常状态比如内存泄漏、死循环或请求急剧增长它会死死锁住 CPU 不放其他进程哪怕想抢占也抢不过。这种“饿死其他人的进程”往往比故障本身更可怕。我们接到过不少现场问题现象是某台机器 SSH 都连不进去查到最后罪魁祸首是某个被调成负优先级的监控脚本在失控循环。所以如果你不是明确知道该进程的资源需求和运行规律建议优先采用“降别人”而不是“升自己”的思路。换句话说遇到资源争抢时先考虑给不重要的任务调高 nice 值再考虑给核心任务调低 nice 值。4.5 实时进程不受 renice 控制这个知识点比较冷门但面试和排障都可能遇到。Linux 的进程调度分为普通调度与实时调度两类。renice 只能作用于普通调度类进程SCHED_NORMAL 等对于实时调度类进程SCHED_FIFO、SCHED_RRnice 值并不会直接决定它们的调度行为实际控制它们的是实时优先级需要用的命令是chrt。如果你对某个进程执行 renice 后发现 nice 值改了但它在系统里该抢还是抢行为完全没变那么很可能它本身就是实时进程或内核线程。普通运维场景中这类进程不多但碰到生产环境有特殊调优的中间件时不能只靠 renice 解决优先级问题。5. 常见问题与排查技巧实录5.1 报错 Operation not permitted 怎么办这个错误最常见的原因就是你当前用户无权调整目标进程。排查思路固定先确认目标进程的归属ps -o user,pid,nice,cmd -p 12345再确认自己是谁id如果进程属于别人你又没有 root 权限那就别再试了需要协调有权限的管理员处理。如果你是 root、还是报这个错大概率是容器 capability 限制或 SELinux/AppArmor 干预这时检查运行环境的安全策略。生产环境中我遇到过很多次在 Docker 容器里调整宿主进程导致报错的情况看起来像权限问题实际上是 namespace 隔离把进程分到了另一个世界连 PID 都不互通这属于架构层面的限制不是命令能解决的。5.2 把数值方向记反了这个坑实在太多人踩。记住口诀nice 值越小优先级越高。所以想让进程更优先用负数想让进程更谦让、让出资源用正数。被这个误操作坑过的同学往往是想“降低”某个任务的占用却把参数写成了负数结果它的优先级更高了系统反而更卡。解决的唯一靠谱办法是调整后立刻复查ps -o pid,nice,pri,cmd -p 12345养成“改完必查”的习惯比什么口诀都有效。5.3 NI 列变了为什么 PR 列没怎么变这类问题在 top 里比较常见。原因是 PR 列在不同系统、不同调度器下并不严格等于 nice 值的线性映射。有些情况下 PR 还受到实时优先级、cgroup 内 CPU 权重等其他因素影响。处理原则很简单查看调整结果时以 NI 列和进程的实际响应为准不要死盯 PR。再说了排查问题最重要的是进程是否按预期运行而不是两个字段是否严丝合缝。你只要确认 NI 变成了目标值且系统负载有所缓解renice 就已经完成使命了。5.4 想开机或重启后依然生效怎么做renice 是一次性命令重启后不会保留。如果你需要长期保证某个任务以特定优先级运行应该在启动该任务的脚本或 systemd unit 里设置。systemd 的做法是在 service 单元的[Service]段写入Nice10普通 Shell 脚本则用启动时的 nice 命令nice -n 10 /usr/local/bin/your_task也就是说renice 适合“临时救火”长期优先级策略应该固化到启动配置里。这也是很多初学朋友容易理解反的地方以为只要调过一次进程就永远保持这个优先级其实父进程重启后一切都得重新设置。5.5 调整以后如何确认效果最佳最后说一个我自己的实用习惯调完之后不要只看系统负载要直接观察目标进程的 CPU 占用变化和响应速度。比较靠谱的做法是在调整前记录一个 baseline调整后再用相同的负载去压一下看看延迟或吞吐有没有变化。用一个简单的循环测试请求耗时比盯着一堆数字猜有效得多。我在实际操作中的体会是renice 是一个“看起来极简、用起来极考判断力”的命令。它解决的问题很单一但什么时候调、调多少、调到谁身上都需要你对整个系统的资源分布有清晰认知。它的价值不在于让你的服务器变飞快而在于让真正重要的任务在关键时刻能跑得起来让不重要的任务不搅局。最后再分享一个小技巧在你不确定某个进程的优先级调整会不会带来连锁影响时先只调一个 PID 观察 10 分钟再决定要不要扩大到用户或进程组。优先级的调整不像装软件可以轻易卸载重来它是在一个共享环境里对运行中进程的现场干预克制和验证比大胆和爽快重要得多。
阅读完成 · 觉得有帮助?
咨询建站