renice 命令详解与参数实测(Ubuntu 22.04)
逐项实测 Ubuntu 22.04 的 renice(util-linux 2.37.2):-n/-p 调整运行中进程、root 调负值与权限边界、普通用户只能调高不能调低、-u 按用户、-g 按进程组(含部分生效现象)、老式写法与多 PID 批量、四类报错 rc=1、降权后调回受限,并与 nice 分工对照,附失控进程降载等实战场景。
renice 命令详解与参数实测(Ubuntu 22.04)
目标:全面掌握 renice 的每一个常用参数与行为——
-n指定新 nice 值、-p按进程 ID、-u按用户、-g按进程组、老式写法与多 PID 批量、普通用户"只能调高不能调低"的权限规则、root 调负值的能力边界、四类报错与返回码,全部命令与回显已在 Ubuntu 22.04(renice from util-linux 2.37.2)实测通过。
一、环境信息
本篇所有命令与回显均在以下环境实测采集,读者在同等环境(Ubuntu 22.04 服务器、util-linux 2.37.2)执行应得到一致结果。
- 操作系统:Ubuntu 22.04.5 LTS(
PRETTY_NAME="Ubuntu 22.04.5 LTS") - 架构:x86_64
- renice 版本:util-linux 2.37.2(
renice from util-linux 2.37.2) - renice 路径:
/usr/bin/renice - 执行身份:root(普通用户限制的对照实验另建了演示用户
reniceu1) - 辅助验证工具:
ps(procps)、su
💡 技术拓展:renice 与 nice 是"同族不同包"的一对工具——nice 是 GNU coreutils 8.32(
/usr/bin/nice),renice 是 util-linux 2.37.2(/usr/bin/renice),两者底层都走 setpriority(2) 系统调用。分工一句话:启动时预设用 nice,运行中改判用 renice——
维度 nice renice 作用对象 只能是它新启动的命令 已在运行的进程/用户/进程组 典型时机 启动时预设(跑批、备份) 运行中干预(降载、提权) 按用户/进程组批量 不支持 支持(-u / -g) 调低(更负)能力 同受 CAP_SYS_NICE/RLIMIT_NICE 约束 同受约束 归属包 GNU coreutils 8.32 util-linux 2.37.2
二、命令概览
2.1 语法与测试数据
renice 的作用是:修改已在运行进程的调度优先级(nice 值)。它有三种等价的目标维度(来自 --help 的 Usage 块):
renice [-n] <priority> [-p|--pid] <pid>... # 按进程 ID(默认)
renice [-n] <priority> -g|--pgrp <pgid>... # 按进程组 ID
renice [-n] <priority> -u|--user <user>... # 按用户名或用户 ID
测试数据:一组 sleep 1000 后台进程当"演示负载",用 ps -o ni 读取 NI 列验证每次调整;普通用户实验使用专用演示用户 reniceu1。全程只操作独立演示进程,不改动系统已有进程。
2.2 --help 全量输出(逐行照抄)
util-linux 风格的 help(注意输出以一个空行开头,-n 的选项名是 --priority 而非 nice 的 --adjustment):
$ renice --help; echo rc=$?
Usage:
renice [-n] <priority> [-p|--pid] <pid>...
renice [-n] <priority> -g|--pgrp <pgid>...
renice [-n] <priority> -u|--user <user>...
Alter the priority of running processes.
Options:
-n, --priority <num> specify the nice value
-p, --pid interpret arguments as process ID (default)
-g, --pgrp interpret arguments as process group ID
-u, --user interpret arguments as username or user ID
-h, --help display this help
-V, --version display version
For more details see renice(1).
rc=0
逐项解读:
| 选项 | 含义 | 实测章节 |
|---|---|---|
-n, --priority <num> | 目标 nice 值(可省略,省略时直接跟数字,见 3.6 老式写法) | 3.1 |
-p, --pid | 后面的参数按进程 ID 解释(默认维度) | 3.1 |
-g, --pgrp | 按进程组 ID 解释,影响该组全部成员 | 3.5 |
-u, --user | 按用户名/UID 解释,影响该用户全部进程 | 3.4 |
2.3 版本信息
$ which renice
/usr/bin/renice
$ type renice
renice is /usr/bin/renice
$ renice --version | head -2
renice from util-linux 2.37.2
type renice 实测返回 /usr/bin/renice——renice 不是 bash 内置命令。版本行只有一个短句(util-linux 风格,区别于 coreutils 工具的两行版权输出),归属包为 util-linux 2.37.2。
三、参数逐项实测
3.1 基本用法:renice -n 5 -p PID
先看目标进程的当前 NI,再调整,再复核——这是 renice 的标准三步:
$ ps -o pid,ni,cmd -p 18318
PID NI CMD
18318 0 sleep 1000
$ renice -n 5 -p 18318
18318 (process ID) old priority 0, new priority 5
$ ps -o pid,ni,cmd -p 18318
PID NI CMD
18318 5 sleep 1000
三个关键观察:
- 回显格式:
<PID> (process ID) old priority <旧值>, new priority <新值>——新旧值一目了然,天然就是变更记录; - -n 的语义与 nice 不同:renice 的 5 是目标值(把 NI 设为 5),nice 的
-n 5是增量(当前值 +5); ps复核 NI=5,调整即时生效(无需重启进程)。
3.2 root 调整为负值与权限边界
把进程往更优先方向调(NI 变负)是特权操作。实测 root 尝试把 3.1 节 NI=5 的进程调到 -5:
$ renice -n -5 -p 18318
renice: failed to set priority for 18318 (process ID): Permission denied
$ ps -o pid,ni,cmd -p 18318
PID NI CMD
18318 5 sleep 1000
如实记录:root 执行后 NI 仍是 5,负值没有生效。原因是本环境 root 的有效能力集不含 CAP_SYS_NICE(内核据此拦截一切"降低 nice 值"的操作),可用 /proc 实测佐证:
$ grep CapEff /proc/self/status
CapEff: 00000000a80425fb
$ ulimit -e
0
$ ulimit -H -e
0
CapEff: 00000000a80425fb 中 bit23(CAP_SYS_NICE,对应 0x800000)为 0;RLIMIT_NICE 软硬限制均为 0,通过 ulimit -e 40 抬升限制换负值的路也被封死(实测报 ulimit: scheduling priority: cannot modify limit: Operation not permitted)。
⚠️ 注意:标准 Ubuntu 服务器上 root 默认持有 CAP_SYS_NICE,同样的命令会返回
18318 (process ID) old priority 5, new priority -5并即时生效。在降权加固的受控环境(如本实验环境)会遇到上方的 Permission denied,排查方法见第五章 Q2。
3.3 普通用户:调高允许、调低被拒
内核规则:无特权用户对自己进程只能调高(增大)nice 值,任何"调低"(包括从 10 调回 5 这种仍为正数的调整)都会被拒绝。完整实测链(演示用户 reniceu1 的进程 18337):
第一步:root 直接跨用户调整——被拒(跨 euid 修改同样需要 CAP_SYS_NICE,连调高都不行):
$ ps -o pid,user,ni,cmd -p 18337
PID USER NI CMD
18337 reniceu1 0 sleep 1000
$ renice -n 6 -p 18337
renice: failed to set priority for 18337 (process ID): Operation not permitted
第二步:用户自己调高自己的进程——畅通:
$ su - reniceu1 -c 'renice -n 3 -p 18337'; echo rc=$?
18337 (process ID) old priority 0, new priority 3
rc=0
$ su - reniceu1 -c 'renice -n 9 -p 18337'; echo rc=$?
18337 (process ID) old priority 3, new priority 9
rc=0
$ ps -o pid,user,ni,cmd -p 18337
PID USER NI CMD
18337 reniceu1 9 sleep 1000
第三步:用户把已提升的值(10)往回调低(到 4)——被拒,rc=1:
$ ps -o pid,user,ni,cmd -p 507
PID USER NI CMD
507 reniceu1 10 sleep 1000
$ su - reniceu1 -c 'renice -n 4 -p 507'; echo rc=$?
renice: failed to set priority for 507 (process ID): Permission denied
rc=1
$ ps -o pid,user,ni,cmd -p 507
PID USER NI CMD
507 reniceu1 10 sleep 1000
把三类操作汇总成权限速查表:
| 操作 | 谁执行 | 方向 | 结果(实测) |
|---|---|---|---|
| renice -n 3 -p 自己的进程 | 普通用户 | 0→3 调高 | ✅ rc=0 |
| renice -n 9 -p 自己的进程 | 普通用户 | 3→9 调高 | ✅ rc=0 |
| renice -n 4 -p 自己的进程 | 普通用户 | 10→4 调低 | ❌ Permission denied rc=1 |
| renice -n 6 -p 他人进程 | root(无 CAP_SYS_NICE 时) | 跨用户 | ❌ Operation not permitted |
| renice -n -5 -p 任意进程 | root(无 CAP_SYS_NICE 时) | 调低 | ❌ Permission denied |
3.4 -u:按用户调整(该用户名下全部进程)
-u 把目标维度从单个 PID 放大到"某用户的全部进程"。标准 root 服务器上这是批量干预的利器;本环境 root 跨用户被拒,改由用户自己执行演示:
$ renice -n 6 -u reniceu1
renice: failed to set priority for 1014 (user ID): Operation not permitted
$ su - reniceu1 -c 'renice -n 10 -u reniceu1'
1014 (user ID) old priority 0, new priority 10
$ ps -o pid,user,ni,cmd -p 507
PID USER NI CMD
507 reniceu1 10 sleep 1000
结果解读:
- 回显标识变为
<UID> (user ID)——1014 是 reniceu1 的 UID,说明这次调整覆盖了该用户名下的全部进程(此处该用户只有 507 一个进程,ps 复核 NI 已到 10); - root 的
-u reniceu1报错同样指向1014 (user ID)——报错对象是"用户维度"而非某个 PID,这是 -u/-g 与 -p 在回显上的区别。
⚠️ 注意:标准 root 服务器上
renice -n 6 -u reniceu1会直接生效,效果等价于把该用户所有进程逐个 renice。生产上对多进程服务(如某业务账号)做整体降载时优先用 -u,避免逐 PID 枚举。
3.5 -g:按进程组调整(含"部分生效"现象解读)
-g 的目标是进程组(PGID,ps -o pgid 所示),不是用户组。它一次影响组内全部成员。先看一个失败但有玄机的案例——目标组里混着"需要降权"和"跨用户"的成员:
$ ps -o pid,ppid,pgid,ni,cmd -p 18306
PID PPID PGID NI CMD
18306 0 18306 0 bash /root/renice-test.sh
$ renice -n 4 -g 18306
renice: failed to set priority for 18306 (process group ID): Permission denied
$ ps -o pid,ppid,pgid,ni,cmd -p 18306 -p 18318
PID PPID PGID NI CMD
18306 0 18306 4 bash /root/renice-test.sh
18318 18306 18306 5 sleep 1000
如实记录并解读:命令报了 Permission denied,但组内 bash 的 NI 确实从 0 变成了 4(0→4 是调高,允许),而 18318 保持 5(5→4 是调低,被拒)、组内还有跨用户成员(更不允许)。内核对进程组的 setpriority 是逐成员应用:能改的改掉,任何一处失败都会让整条命令报错并返回非零——所以"报错"不代表"全都没生效",必须用 ps 复核。
再补一个全部成员都可调高的干净案例,看成功时的回显格式:
$ ps -o pid,pgid,ni,cmd -p 88
PID PGID NI CMD
88 88 0 bash /root/final-test.sh
$ renice -n 8 -g 88
88 (process group ID) old priority 0, new priority 8
$ ps -o pid,pgid,ni,cmd -p 88 -p 99
PID PGID NI CMD
88 88 8 bash /root/final-test.sh
99 88 8 sleep 1000
成功回显的标识是 <PGID> (process group ID);组内 bash 与 sleep 全部变为 NI=8(子进程 99 是在调整后启动、继承了组内新值)。
3.6 老式写法:省略 -n、甚至省略 -p
util-linux renice 保留了老式语法:-n 可省略(直接跟优先级数字),-p 也可省略(裸数字默认按 PID 解释):
$ renice 9 -p 18318
18318 (process ID) old priority 5, new priority 9
$ renice 12 18318
18318 (process ID) old priority 9, new priority 12
$ ps -o pid,ni,cmd -p 18318
PID NI CMD
18318 12 sleep 1000
两种老式写法都能工作,效果与 renice -n 9 -p 18318 一致。建议新脚本统一用 renice -n <值> -p <PID> 的现代写法——老式写法里"数字到底是目标值还是 PID"全靠位置约定,可读性差。
3.7 多 PID 批量调整
-p 后面可以跟多个 PID,一条命令批量调整:
$ renice -n 12 -p 99 102
99 (process ID) old priority 8, new priority 12
102 (process ID) old priority 8, new priority 12
$ ps -o pid,ni,cmd -p 99,102
PID NI CMD
99 12 sleep 1000
102 12 sleep 1000
两个 PID 各自回显一行 old/new,全部成功。对照一个部分成员会失败的场景(调低方向,受限环境):
$ renice -n 2 -p 18318 18358
renice: failed to set priority for 18318 (process ID): Permission denied
renice: failed to set priority for 18358 (process ID): Permission denied
$ ps -o pid,ni,cmd -p 18318,18358
PID NI CMD
18318 12 sleep 1000
18358 4 sleep 1000
💡 要点:多目标时 renice 会逐个尝试并逐个报错(18318、18358 各一行),不会因第一个失败而中止;脚本判断结果要以返回码 + ps 复核双重确认。
3.8 错误处理:四类典型报错与返回码
实测四类最容易遇到的错误,全部 rc=1:
$ renice; echo rc=$?
renice: not enough arguments
Try 'renice --help' for more information.
rc=1
$ renice -n 5 -p 999999; echo rc=$?
renice: failed to get priority for 999999 (process ID): No such process
rc=1
$ renice -n abc -p 18318; echo rc=$?
renice: invalid priority 'abc'
Try 'renice --help' for more information.
rc=1
$ renice -n 5 -u nosuchuser9x; echo rc=$?
renice: unknown user nosuchuser9x
rc=1
报错语义细分值得注意:
| 场景 | 报错 | 阶段 |
|---|---|---|
| 不带任何参数 | not enough arguments | 用法检查,未接触内核 |
| PID 不存在(999999) | failed to get priority ... No such process | 先 getpriority 探测就失败 |
| 优先级非数字(abc) | invalid priority 'abc' | 参数解析阶段 |
| 用户不存在(nosuchuser9x) | unknown user | 用户解析阶段 |
对比 3.2/3.3 节的 failed to set priority ...(set 阶段失败,目标存在但权限不允许)——"get 失败"与"set 失败"的措辞差异可以帮您快速区分"目标错了"还是"权限不够"。
3.9 PR / NI 对照
调整后用 ps 的多列输出核对优先级口径:
$ ps -o pid,pri,ni,stat,cmd -p 18318,18358,18337
PID PRI NI STAT CMD
18318 7 12 SN sleep 1000
18337 10 9 SN sleep 1000
18358 15 4 SN sleep 1000
💡 技术拓展:三列解读(完整口径对照见《nice 命令详解与参数实测(Ubuntu 22.04)》3.8 节)——
列 含义 本环境实测换算 方向 NI nice 值(renice 的直接操作对象),-20~19 即调整目标值 越小越优先 PRI(ps)/ PR(top) 工具展示口径的调度优先级 ps PRI = 19 − NI;top PR = 20 + NI 见方向列 STAT 进程状态(S 睡眠 / R 运行 / D 不可中断 / Z 僵尸) 与优先级无关 — 内核对 SCHED_OTHER 进程的动态优先级为 120 + NI(100~139,越小越优先,见 sched(7))。STAT 里带 N 标记(如 SN)表示该进程的 nice 值被调整过。
四、实战示例
4.1 场景一:失控进程在线降载
某进程 CPU 占用过高又不能停,先把它调到最低优先级(NI=19),让它只在 CPU 空闲时干活:
$ renice -n 19 -p 102
102 (process ID) old priority 12, new priority 19
$ ps -o pid,ni,cmd -p 102
PID NI CMD
102 19 sleep 1000
要点:全程进程不重启、连接不中断, renice 的 old/new 回显就是现成的变更记录。调高方向(12→19)无需任何特权。
4.2 场景二:降权之后的"调回"限制
场景一处理完,想把进程恢复到 NI=0——调低方向需要特权,如实记录本环境的实测结果:
$ renice -n 0 -p 102; echo rc=$?
renice: failed to set priority for 102 (process ID): Permission denied
rc=1
$ ps -o pid,ni,cmd -p 102
PID NI CMD
102 19 sleep 1000
⚠️ 注意:标准 root 服务器(持有 CAP_SYS_NICE)上同样的命令会返回
102 (process ID) old priority 19, new priority 0并即时生效。本环境因能力受限无法演示,这正是 3.2 节权限边界的实战体现——降权容易、恢复有门槛,生产上对进程降权前要评估"以后谁来调回去"。
4.3 场景三:多 PID 批量降载
一组同类工作进程需要整体降载时,一条命令搞定(3.7 节实测的调高方向批量):
$ renice -n 12 -p 99 102
99 (process ID) old priority 8, new priority 12
102 (process ID) old priority 8, new priority 12
PID 较多时配合命令替换生成清单(形态示例:renice -n 12 -p $(pgrep -f worker)),逐个回显便于逐条核对。
4.4 场景四:按用户/进程组维度批量调整
多进程服务按账号隔离时,用 -u 一次覆盖该用户全部进程(3.4 节实测):
$ su - reniceu1 -c 'renice -n 10 -u reniceu1'
1014 (user ID) old priority 0, new priority 10
同一账号下的进程树也可按进程组整体调整(3.5 节实测的成功案例):
$ renice -n 8 -g 88
88 (process group ID) old priority 0, new priority 8
选型建议:单进程用 -p;同一用户的全部进程用 -u;同一作业/脚本派生的进程组用 -g。
4.5 场景五:变更后的三步核验
调整动作完成后,固定做三步核验(均来自本文实测形态):
$ ps -o pid,ni,cmd -p 18318
PID NI CMD
18318 12 sleep 1000
$ ps -o pid,pri,ni,stat,cmd -p 18318,18358,18337
PID PRI NI STAT CMD
18318 7 12 SN sleep 1000
18337 10 9 SN sleep 1000
18358 15 4 SN sleep 1000
第一步回读 NI 确认目标值到位;第二步带 PRI/STAT 看调度口径与进程状态(N 标记确认被 nice 过);第三步(可选)在 top 里观察一段时间内该进程的 CPU 份额变化——NI 只在 CPU 争抢时体现效果(见第五章 Q5,同 nice 篇口径)。
五、注意事项与常见问题
Q1:renice 和 nice 怎么分工?用了 renice 还需要 nice 吗? 互为补充:nice 在启动时预设(只能影响它自己拉起的命令),renice 在运行中改判(还能按 -u/-g 批量)。已经跑起来的进程想改优先级只能 renice——nice 对已运行进程无能为力(详见 nice 篇 3.9 节实测)。两者对"调低"的权限要求完全一致(CAP_SYS_NICE/RLIMIT_NICE)。
Q2:为什么 root 执行 renice -n -5 也报 Permission denied?
内核要求"降低 nice 值"(含跨用户修改)必须持有 CAP_SYS_NICE。本环境实测 root 的 CapEff: 00000000a80425fb 不含该位(3.2 节),RLIMIT_NICE 软硬限制也都是 0,ulimit -e 40 抬升受限同样被拒。排查三步:grep CapEff /proc/self/status 对照 CAP_SYS_NICE(bit23,0x800000)→ ulimit -e 与 ulimit -H -e 看限制 → 确认目标进程的属主(跨用户必被拒)。标准服务器上 root 默认持有该能力,直接生效。
Q3:为什么把进程调"高优先级"很容易,想调回来却报错? 内核把 setpriority 的方向做了不对称限制:调高 nice 值(让路)人人可做、随时可做;调低 nice 值(插队)是特权操作。这形成事实上的"不可逆":普通用户把进程降到 19 后自己永远调不回来,root 调低也要 CAP_SYS_NICE(见 4.2 节实测 rc=1)。生产建议:降权前想清楚恢复路径;对关键服务避免用普通账号做降权操作。
Q4:renice 属于哪个软件包?为什么它的 help/报错风格和 nice 不一样?
renice 来自 util-linux 2.37.2(renice from util-linux 2.37.2,2.3 节实测),nice 来自 GNU coreutils 8.32——两个独立上游,所以 help 排版(Usage 块 vs 逐行描述)、版本输出(一行短句 vs 版权块)、报错措辞(failed to set priority vs cannot set niceness)都不同。底层都是 setpriority(2),语义一致。
Q5:renice 改了 NI,为什么看不出来性能变化? NI 只在 CPU 争抢时起作用。系统空闲时高 NI 进程照样满速跑;瓶颈在内存/磁盘/网络时调 NI 无效。验证调度效果要在 CPU 饱和的场景下对比 top 中同优先级进程的 CPU% 占比,或用 perf 类工具观测调度延迟。
Q6:报错信息里 failed to get priority 和 failed to set priority 有什么区别?
get 失败 = 目标根本不存在或不可见(如 3.8 节的 PID 999999);set 失败 = 目标存在但当前身份无权做该调整(3.2/3.3 节的 Permission denied / Operation not permitted)。看到 get 失败先查目标写没写对,看到 set 失败再查权限与方向。
六、参考链接
- Ubuntu 22.04 (jammy) renice 手册页:https://manpages.ubuntu.com/manpages/jammy/en/man1/renice.1.html
- setpriority(2) 系统调用(优先级调整与权限规则):https://man7.org/linux/man-pages/man2/setpriority.2.html
- sched(7) 调度策略与优先级范围:https://man7.org/linux/man-pages/man7/sched.7.html
- util-linux 官方代码仓库:https://github.com/util-linux/util-linux
- util-linux 官方发布页:https://www.kernel.org/pub/linux/utils/util-linux/