cpulimit适合临时压制,长期服务应优先使用systemd的CPUQuota;它通过SIGSTOP/SIGCONT信号软性限流,非内核级,存在抖动与不精准问题,且无法限制D状态进程、内核线程或绑核进程。

cpulimit 能快速起效,但只适合临时压制;长期服务必须用 systemd 的 CPUQuota;cgroups v2 最灵活但配置门槛高——选哪种,取决于进程生命周期和权限范围。
cpulimit -p 或 -e 限制运行中进程时为什么没反应?
常见现象是执行后 top 里 CPU 占用没变化,或命令直接退出。根本原因不是工具坏了,而是它被进程状态或权限卡住了:
- 普通用户无法限制非自己启动的进程(比如
nginx、mysqld),必须用sudo或切到 root - 目标进程已退出:
cpulimit默认会等待进程出现;加-z参数让它检测不到就立刻退出,避免假死 - 进程由
systemd托管:子进程可能被systemd自动回收,导致cpulimit失效;此时应改用CPUQuota -
-l值设得太低(如-l 1)会导致进程频繁 SIGSTOP/SIGCONT,反而引发调度抖动,实际效果反而变差
systemd 服务用 CPUQuota 限制时为何 reload 后不生效?
CPUQuota 是内核级配额,但依赖 cgroups 正确挂载和启用。reload 成功不代表限制已加载:
- 确认 cgroups v2 已启用:
ls /sys/fs/cgroup/cgroup.subtree_control必须存在,否则 fallback 到 v1 且CPUQuota可能被忽略 -
CPUQuota=50%中的百分号%不可省略,写成50会被当成毫秒值(即 50ms/s),等效于 5% —— 这是最常踩的拼写坑 - 修改完 unit 文件后,必须先
sudo systemctl daemon-reload,再sudo systemctl restart servicename.service;只 reload 不 restart,旧 cgroup 配置仍驻留 - 检查是否生效:
systemctl show servicename.service | grep CPUQuota,再看cat /sys/fs/cgroup/system.slice/servicename.service/cpu.max输出是否为500000 100000(表示 50% 带宽)
cgroups v2 手动限制 CPU 需要哪些关键步骤?
手动操作适合调试或容器外的精细控制,但每步都依赖路径和权限正确:
- 创建 cgroup 目录:
sudo mkdir /sys/fs/cgroup/myapp(注意必须用sudo,普通用户无权写入) - 启用 CPU 控制器:
echo "+cpu" | sudo tee /sys/fs/cgroup/cgroup.subtree_control;若报错“Invalid argument”,说明内核未启用 cpu controller,需检查/proc/cmdline是否含systemd.unified_cgroup_hierarchy=1 - 设置 CPU 带宽:
echo "500000 100000" | sudo tee /sys/fs/cgroup/myapp/cpu.max(前值是 quota,后值是 period,即 50%) - 把进程加入组:
echo PID | sudo tee /sys/fs/cgroup/myapp/cgroup.procs;注意不能用tasks,v2 只认cgroup.procs - 子进程默认继承父 cgroup,但若目标进程 fork 后 exec 新程序,且新程序有 setuid/setgid,可能脱离控制——这是容易被忽略的逃逸点
为什么不用 nice/renice 替代 CPU 限制?
nice 调整的是调度优先级,不是资源上限。它在负载不高时几乎无效,在多核场景下更不可靠:
-
nice值只影响同优先级队列内的竞争,当系统空闲时,低 nice 进程仍可吃满所有 CPU - 在多核机器上,
nice不限制单个进程能跑几个核;一个nice 19的进程仍可能在 4 个核上各占 100%,总占用率达 400% -
cpulimit和CPUQuota是硬限,基于时间片抢占;nice是软提示,内核可忽略 - 唯一适合
nice的场景是:你只想让某个批处理作业“尽量别抢资源”,且接受它在空闲时全速跑完
systemd 配好 CPUQuota,启动中用 cpulimit -z 应急,长期跑在容器里的则直接走 cgroups v2 接口。三者不是替代关系,而是分层补位。


















