11.3 資源治理:Requests & Limits 與 OOM 防護#
沒配額的集群像合租不立規矩:有人開礦機,全屋跳閘。Requests 是「保底」,Limits 是「天花板」。
兩個數字,兩種語義#
resources:
requests:
cpu: "500m" # 保底 0.5 核:調度保證,HPA 算利用率的分母
memory: "512Mi" # 保底 512M
limits:
cpu: "2000m" # 上限 2 核:超了被節流(throttle)
memory: "1Gi" # 上限 1G:超了直接 OOMKilled
flowchart TD
S[Scheduler<br/>看 requests 選 Node<br/>保底加總不能超 Node] --> R[運行時<br/>看 limits 執法]
R -->|CPU 超限| T[被節流 變慢]
R -->|內存超限| OOM[OOMKilled<br/>容器被殺 125 事件]kubectl apply -f deployment.yaml
kubectl describe node | grep -A 5 Allocated # 看保底分配率
kubectl top pods # 需 metrics-server,對比實際用量
經驗法則:requests = 壓測 P50 用量,limits = P99 × 1.2。Java 應用務必讓 -Xmx 小於 memory limit,否則必被誤殺。
QoS 三等級:驅逐時的救生艇順序#
K8s 按配額把 Pod 分三等,Node 資源耗盡時按序驅逐:
| QoS | 條件 | 驅逐順序 | 適用 |
|---|---|---|---|
| Guaranteed | requests == limits(每個容器) | 最後 | 支付、訂單核心鏈路 |
| Burstable | 設了至少一項(常見) | 中間 | 普通微服務 |
| BestEffort | 什麼都沒設 | 最先被殺 | 測試、批處理 |
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name} {.status.qosClass}{"\n"}{end}'
血淚教訓:大促前把核心鏈路設 Guaranteed,邊緣任務設 BestEffort,資源爭搶時死的先是次要的。
# guaranteed.yaml:支付核心鏈路,requests == limits
apiVersion: apps/v1
kind: Deployment
metadata:
name: pay
spec:
replicas: 3
selector:
matchLabels: { app: pay }
template:
metadata:
labels: { app: pay }
spec:
containers:
- name: pay
image: taobao/pay:v2
resources:
requests: { cpu: "1000m", memory: "1Gi" }
limits: { cpu: "1000m", memory: "1Gi" } # 相等即 Guaranteed
kubectl apply -f guaranteed.yaml
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name} {.status.qosClass}{"\n"}{end}'
# 壓測對比:Guaranteed 的 pay 與 BestEffort 的 batch,Node 壓力下誰先被驅逐
kubectl top pods --sort-by=memory
OOM 與驅逐:兩種死法#
- OOMKilled(容器級):單容器超 memory limit,kubelet 直接殺,
kubectl describe pod見Reason: OOMKilled。 - Eviction(節點級):Node 記憶體/磁碟耗盡,kubelet 按 QoS 趕 Pod 下車,
kubectl get events見Evicted。
# 排查三連
kubectl describe pod <pod> | grep -i -A 3 oom
kubectl get events --sort-by=.lastTimestamp | grep -i -E "evict|oom|kill"
kubectl top node # Node 是否被打爆
防護組合拳:合理 limits + HPA(11.2 節)+ PDB + 監控告警(13.2 節)。FinOps 視角:requests 虛高 = 花冤枉錢買閒置,要定期用 VPA / 金絲雀壓測校準。
與前篇呼應#
- 1.3 節單機 CPU/內存競爭,容器時代重演:只是戰場從進程變成 Pod。
- 6.4 節「在我機器上能跑」:缺的就是這組配額聲明,上生產直接打架。
本章小結#
- requests 保調度與 HPA 分母,limits 保上限執法。
- CPU 超限被節流,內存超限被殺,兩者行為完全不同。
- QoS 三等決定驅逐順序,核心鏈路用 Guaranteed。
- OOM 是容器死,Eviction 是節點趕人,排查路徑不同。
- 配額是彈性與成本的基石,下一節解決「 Pod 該住哪、集群怎麼跨機房」。
想一想#
- CPU 與內存超限的後果有何不同?為什麼 CPU 可壓縮、內存不可壓縮?
- 什麼樣的 Pod 會被分到 BestEffort?它在資源緊張時命運如何?
- requests 設得過大或過小,各有什麼代價?(提示:調度、HPA、FinOps)