进程优先级是什么
Linux 是多任务操作系统,同一时刻可能有几十上百个进程在跑。但 CPU 的核心数量是有限的(比如 4 核、8 核),不能所有进程同时运行。内核的调度器(scheduler)决定下一个运行谁、运行多久。这个"谁先谁后"的判断依据就是进程优先级。
优先级在 Linux 里用 "nice value"(谦让值)表示,范围是 -20 到 19。数值越小,优先级越高,越容易抢到 CPU;数值越大,优先级越低,越"谦让"。负数的优先级更高,意味着你调低 nice 值会让进程变得更"霸道"。
我第一次觉得 nice 有用,是在一台 4 核的编译服务器上。当时大家都在往上面提交代码编译,一个普通编译任务能占满 CPU 很多个核,导致其他运维命令(比如 SSH 登录后的操作)都卡得不行。后来我学会了用 nice 把编译任务设成低优先级,遇到系统负载高的时候自动让出 CPU 给更重要的任务。从那以后,这台服务器再也没有出现过 ssh 登录后敲半天没反应的情况。
nice:启动时设置优先级
nice 命令在启动程序时指定优先级。用法很简单:
# 以默认优先级启动程序(默认是 10)
nice ./my-program
# 以更高的优先级(更不谦让),注意普通用户不能设负数
nice -n -5 ./my-critical-job
# 以更低的优先级(更谦让),编译任务常用
nice -n 19 ./long-compile-task
# 简写形式,-n 和直接数字等价
nice -10 ./backup-script.sh
nice 的默认值是 10。所以如果你不加任何参数直接 nice ./program,相当于 nice -n 10 ./program。这意味着它比正常启动(相同终端下的其他进程)更"谦让"一些。
这里要重点说明一个限制:普通用户只能调高 nice 值(让优先级降低),不能调低 nice 值(让优先级变高)。比如普通用户运行 nice -n -5 ./job 会报错,因为调低 nice 值意味着"我要抢更多 CPU",这需要 root 权限。所以:
# 普通用户能做的
nice -n 19 ./low-priority-task.sh
# root 或 sudo 可以做
sudo nice -n -10 ./high-priority-daemon
这个限制是为了防止普通用户恶意抢占 CPU 资源。在多人共享的服务器上,如果每个人都能把自己进程的 nice 值调成 -20,系统基本上就乱了。
我个人的经验:批量处理任务(数据备份、日志压缩、代码编译、批量图片处理)建议都加个 nice -n 19。这些任务对响应时间不敏感,大不了慢一点,但不要影响线上服务的响应速度。
renice:运行时调整优先级
renice 可以在进程运行过程中动态调整优先级,比 nice 更灵活:
# 将 PID 为 1234 的进程优先级调低(更谦让)
renice -n 10 -p 1234
# 将某个进程调高优先级(需要 root)
sudo renice -n -5 -p 1234
# 调整某个用户的所有进程
sudo renice -n 5 -u username
# 调整某个进程组的所有进程
sudo renice -n 10 -g 1234
renice 的参数同样受用户权限限制,普通用户只能降低优先级(调高 nice 值),不能提高优先级(调低 nice 值)。
我有个常用的场景:线上 Web 服务器突发高负载时,CPU 被后台的备份脚本吃掉了。这时候不需要 kill 脚本,只需要 renice -n 19 -p $(pidof backup-script) 把它降级,让出 CPU 给 Nginx 和 PHP-FPM,问题就缓解了。等高峰期过了再把它的优先级恢复到正常值(或者干脆不管,因为它跑完就结束了)。
⚠️ 安全提醒:renice 可以对 root 用户的进程生效吗?不能,普通用户无法 renice 属于 root 或其他用户的进程。即便你是程序的启动者,如果程序启动了子进程并切换了用户(比如通过 sudo 或 su),你也没法 renice 那些子进程。这是一个重要的安全边界。
配合 top 查看 NI 列
调整优先级后怎么确认生效了?top 命令的 NI 列就是看这个的:
# 启动 top,查看 NI 列
top -c
在 top 界面中,NI 列显示的就是 nice 值。如果看不到 NI 列,默认 top 就会显示它(通常在 PR 列的右边)。你也可以按 f 键进入字段管理,按上下键找到 NI 并按下空格选中。
来看看 top 输出中关于优先级的两个字段:
# 在 top 输出中
# PR 是内核实际使用的优先级(对开发者和运维人员来说意义不大)
# NI 才是我们设的 nice 值
top -c -p 1234
输出类似这样:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1234 root 20 0 256000 24500 10240 S 5.0 2.0 0:15.30 important-service
1235 root 35 15 128000 12000 8000 R 90.0 1.0 2:30.10 heavy-compile
PR(Priority)是 20 + NI 换算得到的内核调度优先级。NI: 0 对应 PR: 20,NI: 15 对应 PR: 35,NI: -10 对应 PR: 10。你可以直接看 NI 列,不需要关心 PR 的数值。
在 top 运行中,你甚至可以不需要退出 top 就调整优先级:按 r 键,输入进程 PID,然后输入新的 nice 值。
另外推荐一个工具 htop,它在显示优先级方面更友好:
# 安装 htop(大家用推荐的包管理器安装)
sudo apt install htop # Ubuntu/Debian
# sudo yum install htop # CentOS/RHEL
# 启动 htop
htop
htop 默认就会显示 NI 列,而且彩色显示更直观。不过核心功能 top 也能完成,个人习惯选择。
IONICE:磁盘 IO 优先级
除了 CPU 优先级,Linux 还支持磁盘 IO 优先级,通过 ionice 命令控制:
# 将某个程序以空闲 IO 优先级启动,只有磁盘空闲时才读写
ionice -c 3 ./backup-job.sh
# 将运行中的进程的 IO 优先级设为尽力而为-高优先级
ionice -c 2 -n 0 -p 1234
# 将某个进程的 IO 优先级设为尽力而为-低优先级
ionice -c 2 -n 7 -p 1234
-c 参数指定 IO 调度等级:
- -c 1:实时(Real-time),最高优先级,需要 root
- -c 2:尽力而为(Best-effort),分 0-7 级,0最高
- -c 3:空闲(Idle),只用空闲带宽
-n 参数在 -c 2(尽力而为)下有意义,0 到 7,数值越小优先级越高。
实际场景中,数据库备份、日志归档、大数据量的文件复制这些操作,建议加上 ionice -c 3。这样这些操作不会干扰线上服务的磁盘读写。我在做 MySQL 物理备份(xtrabackup)时,一定会加上 ionice -c 2 -n 7,保证备份不会把数据库拖垮。
注意:ionice 的效果依赖于 IO 调度器(IO scheduler)。传统的 CFQ 调度器(Completely Fair Queuing,完全公平队列)全面支持 ionice,但现在的服务器主流 IO 调度器是 deadline 或者 none(包含 NVMe 硬盘)。在这些新调度器上,ionice 的效果有限。你可以这样检查调度器:
# 查看当前 IO 调度器
cat /sys/block/sda/queue/scheduler
输出可能是 [mq-deadline] none 或者 none,方括号表示当前正在使用的。如果是 none,ionice 基本没用。如果你是在云主机上(阿里云、AWS 等),大概率是 none,这时候 ionice 可以不加。
实际应用场景
场景一:编译时不影响服务器响应
# 写个编译脚本,让编译任务在后台低优先级运行
screen -S compile
nice -n 19 make -j$(nproc)
# 按 Ctrl+A 然后按 D 分离 screen 会话
这时候编译任务虽然在跑,但如果服务器上有其他更重要的事(比如响应 API 请求),进程会自动让出 CPU。
场景二:数据库备份
# 综合使用 nice 和 ionice,CPU 和 IO 都降到最低优先级
nice -n 19 ionice -c 3 mysqldump --all-databases > /backup/db.sql
# 或者用 xtrabackup 做物理备份
nice -n 19 ionice -c 2 -n 7 xtrabackup --backup --target-dir=/backup/full
场景三:调整失控的进程
# 发现某个开发者代码跑了个死循环,但又不想 kill 掉(可能里面有重要数据)
# 先降级,再沟通
sudo renice -n 19 -p 12345
sudo ionice -c 3 -p 12345
# 然后检查它的情况
top -p 12345
这种做法比直接 kill 更温和。降级之后,这个进程虽然还在跑,但已经基本不影响其他服务了。等你确认情况后再决定是否 kill。
优先级调度与 cgroups
对于追求精细化的场景,nice/renice 其实只是 CPU 调度的"粗粒度"工具。在容器化和云原生时代,更主流的做法是用 cgroups(Control Groups,控制组)来做更精细的资源限制:
# 使用 cgroups 限制 CPU 使用比例(需要 cgroup 工具)
sudo cgcreate -g cpu:/limited-group
sudo cgset -r cpu.cfs_quota_us=50000 -r cpu.cfs_period_us=100000 limited-group
sudo cgclassify -g cpu:/limited-group $PID
但 nice/renice 的好处是简单、直接、不需要额外工具。在单机、运维脚本、临时排错场景中,它的效率比 cgroups 高得多。建议你在日常运维中优先掌握 nice/renice,等到了容器规模再去学 cgroups 和 Kubernetes 的资源管理。
总结
nice 和 renice 是 Linux 进程优先级管理的基本工具。nice 在启动时设置,renice 在运行时调整。搭配 ionice 可以同时控制 CPU 和 IO 优先级。关键记住两点:普通用户只能降级不能升级、负数优先级需要 root。掌握了优先级管理,多任务环境下你就能游刃有余地分配系统资源,让关键任务跑得更顺畅,后台任务安安静静地让路。