关于在 Kubernetes 环境中停止使用 CPU 限制的分析与建议

根据 Robusta 的文章《For the Love of God, Stop Using CPU Limits on Kubernetes》以及近期内部发生的多起事故,本文档旨在深入分析在 Kubernetes (K8s) 环境中设置 CPU 限制 (CPU Limit) 的弊端,并结合具体事故案例,提供解决及预防此类问题的最佳实践。核心结论是,在绝大多数情况下,应停止使用 CPU 限制,并专注于精确设置 CPU 请求 (CPU Request),以避免性能瓶颈和不必要的生产事故。


CPU 与内存:可压缩与不可压缩资源的核心差异

理解 CPU 和内存资源在 K8s 中的本质区别,是做出正确资源配置决策的基础。

CPU 是可压缩资源 (Compressible Resource):CPU 的使用是基于时间片的。如果一个容器达到了其 CPU 限制,它会被"节流" (Throttled),即在一段时间内无法被调度,导致应用延迟。然而,这并不会"用尽"节点的 CPU 资源。当下一个时间片到来时,CPU 资源依然可用。文章中将其比作"可再生的水"------即使暂时被一个口渴的人多喝了,水源本身并不会枯竭。

内存是不可压缩资源 (Non-compressible Resource):内存一旦被分配给一个进程,就无法被系统在不终止该进程的情况下收回。如果一个容器试图使用超过其内存限制的内存,它会被 OOMKilled (Out of Memory Killed),直接导致应用崩溃。因此,为内存设置限制是保护节点稳定性的必要措施。

资源类型 特性 限制 (Limit) 的影响 请求 (Request) 的作用
CPU 可压缩 达到限制时,Pod 会被节流,导致性能下降和延迟增加。 保证 Pod 至少能获得的 CPU 资源,避免被其他 Pod 饿死。
内存 不可压缩 达到限制时,Pod 会被 OOMKilled,导致应用崩溃。 保证 Pod 至少能获得的内存资源,是 K8s 调度决策的依据。

为什么 CPU 限制弊大于利?

设置 CPU 限制的初衷是为了防止单个"失控"应用耗尽节点所有 CPU 资源,但这种做法在实践中往往导致更多问题。其根本原因在于 Linux 内核的 CFS (Completely Fair Scheduler) 调度器如何执行 CPU 限制。

当一个容器在单个调度周期内用尽其 CPU 配额时,它会被强制"睡眠",直到下一个周期才能再次被调度。这意味着,即使节点上还有大量空闲的 CPU 资源,这个被限制的容器也无法使用它们,从而导致应用性能无故下降。这就像文章中的比喻:一个人快渴死了,旁边明明还有水,但因为他今天的"限额"用完了,就只能眼睁睁地看着水而不能喝。

精确的 CPU 请求 (Request) 才是保证服务质量 (QoS) 的正确方式。K8s 调度器会确保节点上所有 Pod 的 CPU 请求之和不超过节点的总 CPU 容量。这意味着,只要设置了合理的 CPU 请求,每个 Pod 都能在需要时获得其所请求的 CPU 资源,从而避免了资源争抢导致的"饿死"现象。

💡 核心原则:CPU 是可再生资源,节点上未被使用的 CPU 是对资源的浪费。CPU 请求保障了最低资源供给,而 CPU 限制则人为地阻止了应用利用空闲资源,造成不必要的性能损耗。


内部事故分析:CPU 限制如何导致生产问题

近期发生的多起事故,其根本原因都与不合理的资源限制密切相关,尤其是 CPU 限制。虽然事故报告中未直接将"不合理的 CPU 限制"列为根因,但其表现出的运维特征(如 CPU 饱和、性能下降)与 CPU 节流的症状高度吻合。

事故编号 事故摘要 与 CPU 限制的关联分析
INCI-1183 Meta MySQL 数据库 CPU 使用率高 数据库是典型的对延迟敏感的应用。当查询负载突增时,如果 CPU 限制过低,MySQL 进程会因 CPU 节流而无法及时处理请求,导致查询变慢、连接堆积,最终表现为持续的高 CPU 使用率和性能下降。
INCI-1387 Loki querier 组件 CPU 达到 100% Loki querier 在处理复杂查询时需要消耗大量 CPU。持续的 100% CPU 使用率是 CPU 节流的典型信号,意味着 querier 的潜力被限制住了,无法利用节点的空闲 CPU 来加速查询,导致用户查询超时和失败。
INCI-1456 Cilium agent OOM(内存限制过激) 虽然这是内存限制问题,但它揭示了对关键系统组件(如网络插件)设置过于激进的资源限制所带来的风险。如果对 Cilium 同时设置了不当的 CPU 限制,同样会引发网络延迟、丢包等严重问题,影响整个集群的网络通信。
INCI-1087 Vector agent OOM(遥测管道中断) 此事故再次印证了资源配置不当是导致系统故障的常见模式。无论是 CPU 还是内存,静态且过低的限制都无法适应工作负载的动态变化,最终导致关键的遥测管道中断,影响可观测性。

这些事故共同指向一个结论:静态的、尤其是不合理的低 CPU 限制,是潜伏在系统中的"定时炸弹"。当业务负载超过这个限制时,就会引发性能问题甚至服务中断。随着 GPU 节点的持续扩容,工作负载将进一步增大,若不及时修正资源配置,类似事故将更加频繁。


最佳实践与行动建议

为了从根本上解决此类问题,提升系统稳定性和性能,我们应采纳以下最佳实践:

1. 立即停止使用 CPU 限制

对于绝大多数应用,特别是那些对延迟敏感的服务(如数据库、API 网关、消息队列、网络插件等),应立即移除 resources.limits.cpu 配置。对于少数确实行为不端、可能无限循环消耗 CPU 的"糟糕应用",可以考虑保留限制作为最后的防护栏,但这种情况应属例外,而非惯例。

2. 精确设置 CPU 请求

将工作重心转移到设置准确的 resources.requests.cpu 上。CPU 请求应基于应用在正常负载下的实际使用情况来设定,并留有一定的余量以应对负载波动。可以利用监控数据(如 Prometheus)和自动化工具(如 Robusta 推荐的 KRR - Kubernetes Resource Recommender)来科学地推荐请求值。

3. 统一内存请求和限制

对于内存,最佳实践是始终将 resources.requests.memoryresources.limits.memory 设置为相同的值。这能为 Pod 提供稳定的 Guaranteed QoS 等级,避免因资源争抢而被驱逐,同时也能防止内存泄漏影响到节点上的其他应用。

资源 是否设置 Request 是否设置 Limit 备注
CPU ✅ 必须,且要精确 ❌ 绝大多数情况下不设置 仅对已知行为异常的应用例外设置
内存 ✅ 必须 ✅ 必须,且与 Request 相同 防止 OOMKill 影响节点稳定性

行动计划

建议所有工程师立即对自己负责的服务进行审视,识别那些设置了较低 CPU 限制(如 250m500m12 等)的组件,评估移除这些限制并调整 CPU 请求的可行性,从而在下一次变更中消除潜在的事故隐患。


结论

遵循 K8s 的设计哲学,我们应当信任其调度器通过 CPU 请求来合理分配资源的能力,而不是通过强制的 CPU 限制来束缚应用的性能。通过移除不必要的 CPU 限制,并科学地设置 CPU 请求,我们不仅可以提升应用的性能和响应速度,还能显著减少因资源节流引发的生产事故,从而构建一个更具弹性和鲁棒性的系统。


参考资料

1\] Natan Yellin. (2022). *For the Love of God, Stop Using CPU Limits on Kubernetes (Updated)* . Robusta.dev. [https://home.robusta.dev/blog/stop-using-cpu-limits](https://home.robusta.dev/blog/stop-using-cpu-limits "https://home.robusta.dev/blog/stop-using-cpu-limits")

相关推荐
石工记2 小时前
OpenClaw AI 助手 Docker Compose 一键部署文档(可下载)
人工智能·docker·容器
maotou5262 小时前
Centos7安装docker+redis+pgsql
redis·docker·容器
Hns.2 小时前
自建docker镜像仓库
docker·容器·eureka
隔壁寝室老吴3 小时前
docker安装部署openclaw教程
运维·docker·容器
05大叔3 小时前
Docker
运维·docker·容器
柒.梧.3 小时前
从0到1理解K8s:为什么用、怎么设计、如何搭建
云原生·容器·kubernetes
袁煦丞 cpolar内网穿透实验室4 小时前
Portainer可视化玩转 Docker 全流程。cpolar 内网穿透实验室第 737 个成功挑战
运维·docker·容器·远程工作·内网穿透·cpolar
机 _ 长4 小时前
Docker 容器环境安装配置指南 (CentOS Stream 9)
docker·容器·centos
July_104 小时前
凌晨 3 点的报警:K8s 集...
kubernetes