CPU limit 到底是怎么限制容器的?requests 又在什么时候起作用?这篇直接读 cgroup 的 cpu.max、cpu.weight 和 cpu.stat,用死循环做对照,把限流的计数、没有 limit 的容器能用多少核、竞争时按什么比例分都量出来。
cpu.max=20000 100000(每 100000 微秒的周期里最多 20000 微秒);cpu.weight=17 10.3 秒的窗口里:用掉 CPU 2.06 秒(= 20% 个核);nr_periods=102 nr_throttled=79(77% 的周期被限流);throttled_usec=4.64 秒
limit 200m 在 cgroup 里变成 cpu.max=20000 100000:每 100 毫秒周期里最多跑 20 毫秒。一个死循环想用满整个核,10.3 秒的窗口里只用掉 2.06 秒 CPU(20%);102 个周期里有 79 个用完了配额被停住(nr_throttled),throttled_usec 累计 4.64 秒就是被迫等待的时间。requests 变成 cpu.weight=17,和限流无关。
free4(4 个死循环,没有 limit):cpu.max=max 100000;10.3 秒用掉 CPU 41.3 秒(平均 3.99 个核);被限流的周期占 0% lim1(4 个死循环,limit 1 核):cpu.max=100000 100000;10.5 秒用掉 CPU 10.5 秒(平均 1.00 个核);被限流的周期占 100%
同样 4 个死循环:没有 limit 的容器平均用了 3.99 个核,被限流周期 0%;limit 1 核的只有 1.00 个核,被限流周期 100%。没有 limit 的容器能用到节点上所有空闲的核,所以“requests 设得很小、不设 limit”并不会限制它用多少 CPU。
small(requests 100m,12 个死循环)cpu.weight=17;big(requests 400m,12 个死循环)cpu.weight=49 同一次读取里取两个容器的 cpu.stat,间隔 12 秒:small 用了 28.9 秒 CPU,big 用了 89.2 秒 CPU,比例 big/small = 3.08(两个 cpu.weight 的比例是 2.88);合计 118 秒 ≈ 9.8 个核,节点共有 10 个核,整台节点的忙碌时间是 107 秒)
在同一个节点上各跑 12 个死循环,把 10 个核吃满:requests 100m 的容器 cpu.weight=17,400m 的 cpu.weight=49;同一次读取里量 12 秒,用量分别是 28.9 秒和 89.2 秒,比例 3.08,接近权重比 2.88,合计约 9.8 个核。没有竞争时 requests 不限制任何东西,有竞争时按它的比例分。
w-free(没有 limit):awk 做 2000 万次加法的墙钟时间 4.3 秒 w-500(limit 500m):awk 做 2000 万次加法的墙钟时间 8.4 秒 w-100(limit 100m):awk 做 2000 万次加法的墙钟时间 54.8 秒
awk 做 2000 万次加法:没有 limit 4.3 秒,limit 500m 8.4 秒,limit 100m 54.8 秒。CPU 密集的程序在 limit 下的墙钟时间远大于它真正占用 CPU 的时间。排查延迟毛刺时要看 nr_throttled 与 throttled_usec,只看平均 CPU 使用率会误以为还有余量。