站点图标 梦呓

Kubernetes 资源分配指南:如何科学设置 CPU 与 Memory 的 Request & Limit

前言

在 Kubernetes (K8s) 集群中,服务 YAML 文件里的 resources 配置块往往是被开发者误解最深的区域。面对 requestslimits,许多人的做法是“凭感觉填”或者“抄隔壁项目的配置”。

但实际上,这短短几行 YAML 决定了你的微服务在面对突发流量时是安然度过、被无情限流(Throttling),还是直接崩溃(OOMKilled);也决定了你的 K8s 集群是能够极致降本增效,还是沦为资源浪费的黑洞。

要彻底搞懂参数该怎么设,我们必须先认清 K8s 调度的底层逻辑。

在k8s集群中,我们编写服务yaml的时候有个关键的resources的参数需要填写,但是具体应该怎样设置呢,以下就是我在实际使用过程中的一点思考:

          resources:
            requests:  # 描述服务启动时所需的资源是多少
              memory: "1Gi"
              cpu: "50m"
            limits: # 描述服务最大能使用多少资源
              memory: "3584Mi"
              cpu: "2"

核心基石:K8s 的“瞎眼会计”与 Linux 的“硬核保安”

在决定给服务分配多少资源前,必须理解 K8s 调度和清理资源的两个核心机制:

调度机制:只看账本,不看现实的“瞎眼会计”

清理策略:可压缩与不可压缩资源的冰火两重天

当节点物理资源真正不够用时,Linux 内核与 K8s 节点代理(kubelet)会介入,对 CPU 和内存采取完全不同的镇压手段:

逐个击破:四大参数的设置法则

基于上述底层逻辑,我们来推演这四个参数到底该怎么填。

CPU Request:必须设置,且尽量贴近真实低谷

但结论可以先放在前面:这是一种极其危险的做法,会导致你的服务在集群高负载时“离奇假死”。

我们来拆解这两种情况的底层逻辑:

情况一:既不设 CPU Request,也不设 CPU Limit(最惨的“底层平民”)

当你两个都不写时,K8s 会认为这个 Pod 对 CPU 的需求是 0

情况二:没设 CPU Request,但设了 CPU Limit(触发 K8s 潜规则)

如果你只写了 Limit: 2,而把 Request 留空,K8s 为了防止逻辑冲突,会强制执行一条底层潜规则:自动将你的 CPU Request 填充为等于 CPU Limit 的值。

架构师总结:为什么“10m”的低保也比“不设”强?

绝对不能让 CPU Request 留空。

哪怕你只给它设置一个极小的值,比如 requests.cpu: 10m 或者 50m,在底层意义上也是天壤之别:

当宿主机 CPU 被打爆到 100% 时,这 50m 的 Request 能保证内核依然会硬性切出一小块时间片给你的服务。你的服务处理请求会变慢(比如从 50ms 变成 1s),但绝对不会假死停摆,依然能缓慢但坚定地响应请求。

CPU Limit:建议不设置(Unset)

Memory Request:必须设置,生死攸关

Memory Limit:必须设置,且策略决定命运

两大流派:追求极致稳定 vs 压榨集群资源

在实际生产中,没有绝对的对错,只有业务场景的取舍。请根据你的服务重要等级对号入座:

流派 A:核心保命流(Maximum Stability)

适用场景: 核心交易链路、网关、有状态服务(数据库、中间件)、不支持重试的复杂业务。

配置公式: Memory Request == Memory LimitCPU Limit 不设置

流派 B:极限压榨流(Extreme Cost Squeezing)

适用场景: 无状态 Web 服务、异步计算 Worker、离线跑批任务、可随时安全重启的边缘服务。

配置公式: Memory Request < Memory Limit(例如 Req=500M, Lim=2G),CPU Request 极低CPU Limit 不设置

总结与架构师建议

最后,为读者提供一份简单粗暴的速查表:

| 资源维度 | 参数配置 | 核心作用与架构意义 |
| ———— | ————————- | ———————————————————— |
| CPU | requests = 偏低真实值 | 必须设置。决定集群调度密度,保障 CPU 满载时的最低算力权重。 |
| CPU | limits = 不设置 (Unset) | 建议不设。消除 CFS 限流导致的延迟长尾,利用空闲算力应对突发。 |
| Memory | requests = 高位真实值 | 必须设置。决定在宿主机内存不足时,被驱逐(Eviction)的风险概率。 |
| Memory | limits = 贴近最大峰值 | 必须设置。防止内存泄漏拖垮整个物理节点。 |
| 核心服务 | Mem Req == Mem Lim | 牺牲一定的装箱率(账面资源),换取绝对不被系统无辜连累猎杀的稳定性。 |
| 边缘服务 | Mem Req < Mem Lim | 承担可能被节点驱逐的风险,换取集群机器成本的大幅度降低(超卖)。 |

最佳实践补丁: 如果你选择了“核心保命流”(Req==Lim)又心疼浪费的资源,请不要通过降低 Request 来制造差值,而是应该引入 HPA(水平自动扩缩容)。将单体内存压低,遇到流量洪峰时通过增加 Pod 副本数来抗压,这才是云原生架构“横向扩展”的终极奥义。

突破静态配置的死局:动态扩缩容(HPA & VPA)的底层逻辑

单靠静态设定 RequestsLimits,永远无法完美契合业务流量的波峰波谷。云原生真正的威力在于“按需变形”。

HPA (Horizontal Pod Autoscaler) – 横向分流,对抗高并发的终极武器

千万不要试图用单实例的 CPU 或内存极限去硬扛大促峰值,这既危险又昂贵。

VPA (Vertical Pod Autoscaler) – 垂直修正,治疗“拍脑袋配置”的良药

很多时候,开发人员根本不知道自己的 Java 或 Go 程序到底需要多少内存。

架构师的军火库:资源水位探测与超卖神器

明白了理论,落地时我们需要工具。针对你前面担忧的“为了稳定浪费内存(Req==Lim),为了省钱牺牲稳定(Req<Lim)”的死局,目前业界有以下几款顶级开源工具可以破局。

Robusta KRR (Kubernetes Resource Recommender) —— 监控数据的“提纯器”

这正是你之前导数据的工具。它不改变 K8s 的调度底层,而是作为你的“首席精算师”。

Koordinator (阿里开源) —— 终极

如果你对那 0.5G 被账面锁死的内存耿耿于怀,Koordinator 是解决这个问题的标准答案。它是阿里双十一大规模混部(Colocation)技术的开源版。

Crane (腾讯开源) —— 具有预知能力的智能调度

如果你的集群跑在腾讯云 TKE 上,或者业务有明显的潮汐特性(比如外卖系统中午流量大),Crane 非常合适。

Goldilocks (Fairwinds) —— 轻量级 Baseline 工具

终极总结:现代云原生微服务资源配置蓝图

作为集群的管理者,你可以按照以下路径构建你的资源防线:

  1. 第一层(配置基线): 借助 Robusta KRRGoldilocks,为所有服务刷上基于历史数据的 Baseline。核心服务锁死 Mem Req == Mem Lim,拔掉 CPU Limit
  2. 第二层(弹性抗压): 依托科学的 CPU Request 设定,全面铺开 HPA。用增加副本数来应对突发,而不是靠单 Pod 的内存硬扛。
  3. 第三层(极致压榨): 如果集群规模足够大,机器成本成为痛点,引入 Koordinator。将无状态后台任务与核心微服务混合部署,吃干榨净每一兆物理内存。
退出移动版