【背景】
我维护一套 12 节点(16C64G,K8s 1.28,containerd 1.7)的自建集群,跑着 40+ 个服务(Java/Go 混合)。过去半年被资源限额问题坑了两次:
- 第一次:一个 Go 服务没设 CPU limit,GOMAXPROCS 默认拉满 16 核,压测时把同节点的 MySQL sidecar 的 P99 从 8ms 打到 45ms,CPU steal 飙到 30%+;
- 第二次:一个 Java 服务设了 2C limit(request 1C),业务高峰期 GC 线程被 CFS throttle 截断,CPU throttling ratio 飙到 8%,P99 从 35ms 直接到 210ms。
两次都是"配错了",但方向相反——一次该设没设,一次设了反而更差。
【常见做法(我观察到的三种流派)】
- 全设派:requests 和 limits 都设,CPU 和 Memory 都锁死。好处是调度可预测、邻居安全;坏处是弹性差,突发流量时直接 429 或 throttle。
- 只设 requests 派:Memory 设 request + limit(防 OOM),CPU 只设 request(保最低份额),不设 limit(让弹性跑满)。好处是突发友好;坏处是 noisy neighbor 问题,尤其在混部场景。
- 按负载类型分派:在线服务设 CPU limit,batch/CI/离线任务不设 limit。折中,但边界不好划。
【我的倾向和理由】
在线服务(有 SLO 的):CPU 和 Memory 都设 limit,但 limit = 2×request,而不是 1:1。
理由:
- 不设 CPU limit 的弹性是"虚假弹性"——CFS 调度下,没有 limit 的容器确实能跑满核,但同节点其他容器会被挤压,整体 P99 反而恶化(我上面第一次事故就是);
- 设 limit 的 throttle 问题真实存在,但可以通过
cpu.cfs_burst_us(内核 5.14+)缓解:允许容器在 throttle 窗口内"攒"CPU 时间用于突发,JVM GC 场景实测 P99 能回 30-40%; - 2:1 的 limit:request 比例给了 100% 的突发空间,同时把上限锁在 2 倍,不会把节点打穿。
离线/batch 任务:CPU 不设 limit,Memory 设 limit。
- batch 任务没有 SLO,throttle 直接伤 throughput,不设 limit 合理;
- 但 Memory 必须设 limit,否则一个 OOM 把节点带崩。
关键前提:这套策略的前提是节点上没有混部在线 + 离线负载,或者用 taint/toleration 做了物理隔离。混部场景下,CPU limit 是"保命"的,不是"可选"的。
【想听大家聊的】
- 你们线上在线服务的 CPU limit:request 比例是多少?1:1 还是 2:1 还是其他?依据是什么(压测数据?经验值?)
cpu.cfs_burst_us你们开了吗?开了之后 throttle 改善多少?有没有副作用?- 混部场景下,你们用 taint 隔离还是靠 limit 硬扛?实际效果差多少?
- 你们有没有遇到过"limit 设了反而比不设更差"的场景(排除 1:1 的极端 case)?
不是要争出个标准答案——我想收集不同规模(5 节点 vs 500 节点)、不同负载(纯 Java vs 纯 Go vs 混合)下的真实配置和数据,攒一个决策矩阵出来。
0赞
0收藏
0楼层