平均CPU够用吗?聊聊被忽视的CFS节流

平均CPU够用吗?聊聊被忽视的CFS节流

_

我们在生产环境遇到一个Go函数偶尔超时。奇怪的是,用户报告CPU利用率看起来"正常"。排查几周后,我们发现问题根本不在整体CPU使用率,而在Linux内核的一个隐藏机制——CFS节流。

为什么只看平均CPU会踩坑

打开任务管理器或top命令,第一眼通常看平均CPU。这个指标教会每一代工程师:CPU高就意味着慢。但这个直觉在容器时代失效了。

关键问题在于:CPU利用率与等待时间不是线性关系。从10%增到11%,延迟几乎不变;但从80%增到81%,等待时间会增加约20倍。这是因为Linux内核的完全公平调度器(CFS)使用时间片轮转——当CPU资源变紧张时,等待队列开始形成。即便只到80%利用率,延迟已经悄然爬坡。

平均CPU回答的是"钱花得值不值",这对IT成本核算有意义,但对延迟敏感型服务,它忽略了一个致命因素:瞬时争抢。

CFS节流如何炸掉你的请求

当你给容器设置CPU限制(比如2000m,即2核)时,内核把这解读为一个时间预算。CFS默认100毫秒一个周期,在此周期内,容器内所有进程累计只能运行200毫秒时间。

假设你的HTTP服务突发处理一个重请求,在4核机器上可能在50毫秒内就烧光整个周期的时间预算。此时另一个请求进来,会被强制等待——这就是CFS节流。即便此时平均CPU显示只有40%(远低于你设置的80%扩容阈值),p99延迟已经飞天。

我们的Go函数就是这样死掉的:某个goroutine在此前的周期内已经消耗完预算,后续的goroutine被节流到超时。2019年Google工程部也报告过类似案例——分了4.1核,实际使用不到1核,却几乎每个100毫秒周期都被节流。

如何看到隐藏的节流

答案在容器的cgroup文件中。执行:

kubectl exec <pod> -- cat /sys/fs/cgroup/cpu.stat

关键指标有两个:nr_throttled(被节流的周期数)和throttled_usec(总计被冻结的微秒数)。如果这两个数字在持续增长,说明你的服务正被静默节流,而平均CPU可能显示一切正常。

对于虚拟机级别的问题,还需要关注%steal(窃取时间),这是hypervisor层面抢走的时间,同样不会体现在Guest OS的平均CPU里。Kube-prometheus提供的CPUThrottlingHigh告警默认是关闭的,因为大多数集群只要设了限制就会触发——这恰恰说明问题的普遍性。

编注:材料来自作者博客,基于Cloud Native Aachen Meetup 2026演讲整理,中文写作时侧重机制解说


凤凰记者亲历乌军无人机无差别攻击:距前线百公里外仍遭波及 2026-05-22
加州电池储能暴增30倍:一场用储能代替燃气的电网革命 2026-05-22