CFN Cloud
Cloud Future New Life
en zh
2025-12-29 · 0 次浏览

Kubernetes Tips:Requests & Limits(别踩坑版)

把 CPU/内存 requests 与 limits 讲清楚:调度、限流、OOMKilled、QoS、HPA/VPA 与容量规划。

资源配额是让集群“看起来很稳”或“莫名其妙不稳”的最快开关之一。很多线上抖动并不是代码突然变差,而是 requests/limits 写法不合理、或者和 HPA/节点容量的假设不一致。

一句话结论(先记住这个)

  • 所有容器都要设置 requests(CPU + 内存):调度器用它来决定 Pod 放到哪里。
  • CPU limits 要谨慎:CPU 上限会触发 CFS quota,负载一上来可能被节流,延迟飙升但你还以为“CPU 不高”。
  • 内存 limits 很重要:没有内存上限,单个容器可能把节点内存吃穿,拖垮同节点其他业务;有上限则要面对 OOMKilled。
  • HPA 默认基于 requests:requests 不准,自动扩缩容就会不准。

调度器到底看什么

Kubernetes 调度(bin packing)主要基于 requests

  • 你写的 requests.cpurequests.memory 决定这个 Pod “占用”多少资源用于放置。
  • limits 主要影响运行时资源限制(尤其 CPU 限流、内存 OOM)。

如果你不写 requests:

  • CPU request 默认等于 0
  • 内存 request 默认等于 0

这种 Pod 很容易被调度进任何节点,但也更容易成为“噪音邻居”:流量突增时它会把资源抢走,导致同节点业务整体抖动。

一个靠谱的起步模板(很多服务够用了)

resources:
  requests:
    cpu: "250m"
    memory: "256Mi"
  limits:
    memory: "512Mi"

这个组合背后的思路:

  • requests 让调度与容量规划可预测
  • memory limit 保护节点不被单个容器拖死
  • 先不设 CPU limit(或留足余量),避免节流导致的延迟尖刺

CPU:requests 用于放置,limits 用于节流(并可能伤害延迟)

CPU 是“可压缩资源”。当 CPU 不够时,进程通常不会崩,而是变慢。

  • requests.cpu:调度和扩容计算的基础(很多指标会以它为分母)
  • limits.cpu:运行时的 CFS quota 上限,超过就会被 throttling(节流)

一个很典型的坑:

你看到 CPU usage 似乎不高,但 p95/p99 延迟突然升高;原因可能是被节流,尤其在突发流量或 GC/加密握手等瞬时 CPU 峰值场景。

建议:

  • 一定保证 limits.cpu >= requests.cpu
  • 对突发型服务不要把 CPU limit 设得太贴近 requests;否则“短时间需要多一点 CPU”都拿不到

内存:limits 保护节点,但要接受 OOMKilled 的现实

内存不是可压缩资源。容器超过内存上限,通常会被内核 OOM killer 终止,Kubernetes 显示 OOMKilled 并重启。

排查 OOM 的第一步:

kubectl describe pod <pod> | rg -n "OOMKilled|Killed"

常见应对路径:

  • 提高 limits.memory(同时评估成本与密度)
  • 优化程序内存(缓存策略、泄漏、对象生命周期)
  • 引入 VPA 做推荐(即使不自动应用也很有价值)

requests/limits 还会影响 QoS(驱逐优先级)

Kubernetes 会按 requests/limits 计算 Pod 的 QoS

  • Guaranteed:每个容器 CPU/内存都设置 requests 与 limits,且相等(requests == limits
  • Burstable:设置了部分 requests/limits,但不满足 Guaranteed 条件
  • BestEffort:完全没有 requests/limits

在节点内存压力下,通常:

BestEffort 先被驱逐,其次 Burstable,最后 Guaranteed。

快速查看某个 Pod 的 QoS:

kubectl get pod -n <ns> <pod> -o jsonpath='{.status.qosClass}{"\n"}'

HPA 的分母问题:CPU 利用率通常除以 requests

很多集群里 HPA 的 CPU utilization 算法近似是:

当前 CPU 使用量 / CPU requests

因此:

  • requests 写太高:HPA 认为“利用率很低”,扩容会偏慢
  • requests 写太低:HPA 认为“利用率很高”,扩容会偏激进

如果你发现:

  • 峰值时扩容不及时
  • 或者平时无意义扩容/缩容抖动

第一优先级就该回头检查 requests 是否贴近“真实稳定负载”。

还要考虑节点 Allocatable(不是 Capacity)

节点的物理资源(Capacity)并不等于可分配给 Pod 的资源(Allocatable)。系统预留、kubelet 预留、驱逐阈值都会吃掉一部分。

排查“理论上能放下,实际放不下”:

kubectl describe node <node> | rg -n "Allocatable|Allocated resources|Capacity"
kubectl get events -A --sort-by=.lastTimestamp | rg -n "Evicted|MemoryPressure"

Sidecar / initContainer:别忘了隐藏成本

很多生产 Pod 带 sidecar:

  • service mesh(Envoy)
  • 日志/监控 agent
  • 安全组件

这些容器同样需要 requests/limits,并且会显著改变 Pod 的总资源画像。只给主容器配资源,常常会让你“以为 300Mi”,实际 Pod 轻松 600Mi+。

initContainers 也要注意:

  • 迁移、warmup、下载等行为可能很吃 CPU/内存
  • 大规模滚动升级时,initContainer 的峰值会叠加,可能造成节点压力

用 LimitRange / ResourceQuota 做“护栏”

为了避免团队成员忘记写 requests/limits,常见做法是用:

  • LimitRange:提供默认值与 min/max,防止极端配置与“全空”
  • ResourceQuota:限制命名空间总配额,并可强制要求 requests/limits

示例(仅示意,按你们平台标准调整):

apiVersion: v1
kind: LimitRange
metadata:
  name: defaults
  namespace: app
spec:
  limits:
    - type: Container
      defaultRequest:
        cpu: 100m
        memory: 128Mi
      default:
        memory: 512Mi

选数值的实战方法(可落地的闭环)

  1. 先用保守模板上线(requests 写上;memory limit 写上;CPU limit 先不写)。
  2. 观察 1–2 周真实流量下的:
  • 内存峰值(p95/p99)
  • CPU 峰值与是否节流(如果设了 limit)
  • OOMKilled、重启频率
  • HPA 的扩缩容节奏(是否晚/是否抖)
  1. 迭代:
  • 内存经常逼近上限:提高 limit 或优化内存
  • 延迟尖刺:检查 CPU throttling、requests/limits 的比例
  • HPA 不准:先修 requests,再谈 HPA 参数
  1. 引入 VPA 做推荐(Off/Initial 先走一段),逐步自动化。

最后一句话(真正的底线)

先把 requests 写对,再把 memory limit 写上;CPU limit 只有在你能接受并量化节流影响时再加。

参考链接

FAQ

Q: requests 要等于 limits 吗? A: 只有需要强保证时才这样设置;多数服务用 Burstable 即可。

Q: 为什么会 OOMKilled? A: memory limit 太小或峰值过高,调整 limit 并结合监控。

Q: 限制会影响调度吗? A: 调度主要看 requests;limits 用于运行时约束和驱逐压力。