Sau bài này bạn làm được: đặt requests/limits dựa trên số liệu thật; hiểu QoS class ảnh hưởng eviction thế nào; debug pod OOMKilled và CPU throttle theo đúng trình tự.

Bài chuyên sâu: Kubernetes requests/limits: CPU throttling và OOMKilled đi chi tiết hơn về cơ chế kernel cgroup, cách đo metric, và chiến lược cho từng ngôn ngữ (Go, JVM, Node.js, Python).


Requests vs limits — hai con số, hai vai trò

requestslimits
Ai dùngSchedulerKernel (cgroup)
Mục đíchĐặt pod lên node nàoGiới hạn runtime
VượtPod dùng nhiều hơn request nếu node rảnhCPU: throttle. Memory: OOMKill
resources:
  requests:
    cpu: "200m"          # Scheduler: cần 0.2 core
    memory: "256Mi"      # Scheduler: cần 256 MiB
  limits:
    memory: "512Mi"      # Kernel: kill nếu vượt 512 MiB
    # cpu limit: thường KHÔNG đặt (xem lý do bên dưới)

CPU throttling

CPU limit = kernel cgroup cpu.cfs_quota_us. Container dùng hết quota trong period (100ms) → bị pause đến period sau.

Triệu chứng: P99 latency spike, CPU util trung bình thấp, container_cpu_cfs_throttled_seconds_total tăng.

Khuyến nghị: đặt CPU request luôn, CPU limit thường không đặt (hoặc rất rộng). Lý do: CPU là compressible — thiếu CPU chỉ chậm, không crash. Scheduler + request đảm bảo fairness.

Ngoại lệ cần limit: multi-tenant cluster, batch workload cần predictable runtime.

# Phát hiện throttling
sum by (pod) (
  rate(container_cpu_cfs_throttled_seconds_total{pod=~"my-app-.*"}[5m])
)

Memory OOMKilled

Memory là incompressible — không thể “chạy chậm để dùng ít RAM”. Vượt limit → kernel cgroup OOM killer → SIGKILL (exit code 137).

kubectl describe pod my-app
# Last State: Terminated
#   Reason: OOMKilled
#   Exit Code: 137

# Debug:
# 1. Metric memory_working_set_bytes trước khi OOM
# 2. App có memory leak? Heap dump (Go pprof, JVM -XX:+HeapDumpOnOutOfMemoryError)
# 3. Tăng limit hay fix leak? Tăng limit mà leak → chỉ trì hoãn

Khuyến nghị: memory luôn đặt limit. Leak của 1 pod không tràn sang pod khác. limit ≈ request × 1.5–2.


QoS class

ClassĐiều kiệnEviction priority
GuaranteedMọi container: requests = limits (CPU + memory)Cuối cùng (ưu tiên cao nhất)
BurstableCó ít nhất 1 request, nhưng request ≠ limitGiữa
BestEffortKhông có request lẫn limitĐầu tiên (dễ bị evict nhất)

Ảnh hưởng thực tế

Khi node memory pressure (dưới evictionHard threshold):

  1. BestEffort bị evict trước.
  2. Burstable vượt requests bị evict tiếp.
  3. Guaranteed cuối cùng.

Node OOM killer dùng oom_score_adj: BestEffort ~1000, Guaranteed -997.

Workload quan trọng (API chính) → Guaranteed. Background worker → Burstable chấp nhận được.


Node scheduling và capacity

Scheduler kiểm tra: sum(pod.requests) trên node ≤ node.allocatable.

# Xem allocatable
kubectl describe node <name> | grep -A6 Allocatable

# Xem đã dùng bao nhiêu
kubectl describe node <name> | grep -A6 "Allocated resources"

Pod Pending “Insufficient cpu” → sum requests trên tất cả node đã vượt allocatable. Giải pháp: (1) giảm requests; (2) scale node; (3) xem pod nào chiếm nhiều.

Request quá lớn so với node

Ví dụ: pod request 8Gi memory, node allocatable 7.5Gi → pod không bao giờ schedule. Kiểm tra Events.


Đặt giá trị dựa trên số liệu

Đừng đoán. Quy trình:

  1. Đo baseline: chạy app ở load thực tế vài ngày.
  2. Metric: container_memory_working_set_bytes P95, container_cpu_usage_seconds_total P95.
  3. CPU request ≈ P95 CPU × 1.2.
  4. Memory request ≈ P95 working set × 1.2.
  5. Memory limit ≈ request × 1.5.
  6. CPU limit: bỏ hoặc đặt 4× request.
  7. Review sau 1-2 tuần với data mới.

VPA (Vertical Pod Autoscaler)

VPA đề xuất requests/limits dựa trên usage lịch sử. Dùng ở mode Off (chỉ recommend, không auto apply) cho production critical.


Checklist nhanh

  • Mọi container có requests (CPU + memory).
  • Memory có limits, không quá sát request.
  • CPU limit: không đặt (hoặc rất rộng), trừ khi multi-tenant.
  • QoS phù hợp: API chính → Guaranteed, worker → Burstable OK.
  • Dashboard có panel throttling + OOM events.
  • LimitRange + ResourceQuota cho namespace shared.
  • Review requests/limits mỗi quý.

Tóm tắt

  • requests cho scheduler + HPA; limits cho kernel cgroup.
  • CPU throttle gây latency spike — thường không nên đặt CPU limit.
  • Memory OOMKilled — luôn đặt limit; vượt = kill, không warning.
  • QoS class quyết eviction order: Guaranteed > Burstable > BestEffort.
  • Đặt giá trị từ metric thật, review định kỳ.

Chi tiết sâu hơn: Kubernetes requests/limits: CPU throttling và OOMKilled.


Câu hỏi hay gặp

Pod Guaranteed nhưng vẫn bị OOMKilled — tại sao?

Trả lời: Guaranteed chỉ ưu tiên khi node eviction (kubelet chọn ai evict). OOMKilled trong cgroup xảy ra khi container vượt chính limit của nó — QoS class không can thiệp. Tăng limit hoặc fix leak.

Requests 100m CPU nghĩa app chỉ dùng được 10% core?

Trả lời: Không. requests không limit runtime. 100m = scheduler đảm bảo ít nhất 10% core time. Nếu node rảnh, pod có thể dùng nhiều core hơn (trừ khi có CPU limit).

Nên đặt requests = limits cho tất cả pod?

Trả lời: Đặt bằng → QoS Guaranteed → ưu tiên eviction cao nhất. Nhưng mọi pod Guaranteed = cluster không overcommit, cần nhiều node hơn. Thực tế: API chính = Guaranteed, worker/batch = Burstable để tận dụng resource.


Bài tiếp theo (Giai đoạn V): HPA, PDB và an toàn rollout — auto-scale và disruption budget.