bigywater.tech
Docker · 39

CPU 限制:--cpus、--cpu-shares 与 cpuset 的区别

--cpus 和 --cpu-shares 都是限制 CPU,有什么区别?一个是硬上限,另一个只在争抢时起作用。这篇用满负荷的 Python 进程,从 cgroup 的 cpu.stat 里读出实际占用的 CPU,逐项验证。

0.50 / 1.00 / 2.02
--cpus 0.5、1、2 的容器满负荷时的平均 CPU 占用(不限制时 9.72)
2.00
--cpu-shares 2(最低权重)的容器在没有竞争时的 CPU 占用
1.57
同一 CPU 上 shares 1024 对 512 的容器,实际占用比例(按 shares 本应 2.00)

硬上限:--cpus 和 --cpu-quota

实测 · 本机执行输出
  不限制:cgroup 里 cpu.max=max 100000 cpu.weight=100;用 12 个进程满负荷跑 6 秒,平均占用 9.72 个 CPU
  --cpus 0.5:cgroup 里 cpu.max=50000 100000 cpu.weight=100;用 12 个进程满负荷跑 6 秒,平均占用 0.50 个 CPU
  --cpus 1:cgroup 里 cpu.max=100000 100000 cpu.weight=100;用 12 个进程满负荷跑 6 秒,平均占用 1.00 个 CPU
  --cpus 2:cgroup 里 cpu.max=200000 100000 cpu.weight=100;用 12 个进程满负荷跑 6 秒,平均占用 2.02 个 CPU
  --cpu-quota 25000(周期默认 100000):cgroup 里 cpu.max=25000 100000 cpu.weight=100;用 12 个进程满负荷跑 6 秒,平均占用 0.25 个 CPU

--cpus 0.5 在容器的 cgroup 里是 cpu.max = 50000 100000(每 100 ms 周期最多用 50 ms),满负荷的容器稳定在 0.50 个 CPU;--cpu-quota 25000 是 0.25。不限制时 12 个进程占用了 9.72 个 CPU(虚拟机共 10 个)。这是 CPU 时间的上限,容器可以在多个核上同时跑,只是总和不超过。

软权重:--cpu-shares

实测 · 本机执行输出
  只有这一个容器、--cpu-shares 2(最低权重)、2 个满负荷进程:平均占用 2.00 个 CPU(没有竞争时 shares 不限制)
  两个容器钉在同一个 CPU(--cpuset-cpus 0)上同时满负荷跑:
    shares 1024 对 1024:占用 0.50 对 0.51 个 CPU,实际比例 0.98;shares 比例 1.00
    shares 1024 对 512:占用 0.63 对 0.40 个 CPU,实际比例 1.57;shares 比例 2.00
    shares 1024 对 256:占用 0.74 对 0.30 个 CPU,实际比例 2.47;shares 比例 4.00
    shares 2048 对 256:占用 0.83 对 0.26 个 CPU,实际比例 3.19;shares 比例 8.00
  --cpu-shares 换算成 cgroup v2 的 cpu.weight:256 → 35,  512 → 59,  1024 → 100,  2048 → 174(不带参数时是 100)
  用 cpu.weight 算出的比例:1024:512 = 1.69,1024:256 = 2.86,2048:256 = 4.97

shares 只决定争抢时的比例。没有竞争时,shares 为 2 的容器也用满 2.00 个 CPU;把两个容器钉在同一个 CPU 上,1024 对 1024 各约一半,1024 对 512 是 0.63 对 0.40。cgroup v2 把 shares 换算成 cpu.weight(1024 → 100,512 → 59,256 → 35,2048 → 174),这个换算不是线性的。实际比例比 shares 的比例小,也比 weight 的比例小一些,我没有深究原因;每组只跑了一次 6 秒。

分步演示

CPU 限制
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Docker Desktop(Engine 29.8.2,容器跑在 Docker Desktop 自带的 Linux 虚拟机里,内核与宿主机的 macOS 不同);镜像为 linux/arm64;需要看虚拟机内部时用特权容器 + nsenter;计时用 time / date +%s%N,数字每次运行会有小幅抖动。Docker Desktop 虚拟机 10 个 CPU;满负荷程序是 python 的多进程忙等循环,占用 = 容器 cgroup 的 cpu.stat usage_usec 增量 ÷ 实际耗时;竞争实验用 --cpuset-cpus 0 把两个容器钉在同一个 CPU;每组运行一次;实验后已删除容器和镜像
    • 没有验证:CPU 节流次数(见后面的 throttling 一篇)、cgroup v1 的行为、--cpuset-cpus 之外的 NUMA、不同内核调度器版本、超线程对占用的影响、docker update 动态调整
    京ICP备2026067502号-1京公网安备11010502063487号