Kubernetes Requests vs Limits: Vì Sao Pod Bị OOMKilled Thoát Mã 137?
Trong Kubernetes, hiện tượng Pod đang chạy bình thường bỗng dưng chuyển sang trạng thái OOMKilled, số lần RESTARTS tăng liên tục rồi kẹt cứng ở CrashLoopBackOff là một trong những sự cố phổ biến nhất. Kiểm tra kubectl describe pod bạn sẽ thấy: Exit Code: 137.
Con số 137 có ý nghĩa toán học: 128 + 9 = 137, nghĩa là tiến trình bên trong container đã bị Linux Kernel gửi tín hiệu SIGKILL (Signal 9) cưỡng chế tắt thở ngay lập tức mà không kịp đóng kết nối hay ghi log!
1. Phân biệt bản chất: Requests vs Limits
| Tiêu chí | Requests | Limits |
|---|---|---|
| Ai sử dụng? | kube-scheduler (Bộ lập lịch) | Linux Kernel cgroups (thông qua Kubelet) |
| Công dụng | Đặt chỗ trước tài nguyên trên Node | Đặt trần cứng mức tối đa container được phép chạm tới |
| Độ co giãn | Mềm (Soft reservation) | Cứng (Hard limit) |
| Khi vượt ngưỡng | Container vẫn chạy nếu Node còn dư RAM/CPU | CPU: Bị bóp (Throttled) Memory: Bị OOM Killer bắn hạ ngay lập tức! |
2. Vì sao vượt CPU chỉ chậm, nhưng vượt RAM lại chết?
- CPU là tài nguyên có thể nén được (Compressible Resource):
Khi ứng dụng dùng vượt quá CPU limit, Linux kernel sử dụng cơ chế CFS (Completely Fair Scheduler) Quota để bóp thời gian chạy của tiến trình trong mỗi chu kỳ 100ms. Ứng dụng chạy chậm đi, độ trễ (latency) tăng cao, nhưng ứng dụng không bị crash. - Memory là tài nguyên KHÔNG THỂ nén được (Incompressible Resource):
Bộ nhớ RAM đã cấp cho một tiến trình thì không thể bóp nhỏ lại. Khi container vượt quamemory.maxquy định trong cgroup, Linux Kernel buộc phải kích hoạt cơ chế Out-Of-Memory Killer (OOM Killer) để bảo vệ tính toàn vẹn của cả máy chủ vật lý.
3. Hiện tượng Node-Pressure Eviction
Ngoài việc container tự chết vì chạm limit, còn một nguyên nhân khác: Cả Node máy chủ cạn kiệt RAM!
Khi RAM trống của Node xuống dưới ngưỡng an toàn (thường là 100Mi), Kubelet sẽ tự động trục xuất (Evict) các Pod để cứu Node dựa trên phân hạng chất lượng dịch vụ (QoS Class):
- BestEffort (Bị đuổi đầu tiên): Pod không cấu hình bất kỳ requests hay limits nào.
- Burstable (Bị đuổi thứ hai): Pod có requests < limits và đang sử dụng vượt quá mức requests đã xin.
- Guaranteed (An toàn nhất): Pod có requests == limits cho cả CPU và Memory.
4. Công thức định lượng tài nguyên chuẩn Production
- Đo đạc trước, không đoán mò:
Sử dụng PromQL theo dõi lượng RAM thực tế sử dụng (container_memory_working_set_bytes) trong vòng 14 ngày, lấy giá trị ở phân vị p95 hoặc p99. - Cấu hình Memory: Request == Limit:
Thiết lậprequests.memory = limits.memorybằng p99 + 25% dung sai dự phòng. Điều này đưa Pod vào nhóm QoS Guaranteed, loại bỏ hoàn toàn rủi ro bị Kubelet evict khi máy chủ biến động. - Cấu hình Heap cho Java / Node.js:
Với Java runtime, luôn đặt cờ-XX:MaxRAMPercentage=75.0để chừa 25% RAM ngoài Heap cho Metaspace, Thread stack và JVM overhead, tránh việc Heap chưa đầy mà container đã bị kernel OOMKilled!
