Hiểu Đúng Về Affinity và Anti-Affinity trong Kubernetes

Kubernetes Scheduler là thành phần đứng sau việc quyết định Pod nào chạy trên Node nào. Tuy nhiên, để điều khiển cụ thể hơn — ví dụ, "Các replica không nên nằm chung node", hay "Pod A và Pod B nên chạy cùng node" — bạn sẽ cần dùng đến Affinity và Anti-Affinity.
Trong bài viết này, mình sẽ giúp bạn:
Hiểu rõ về Node Affinity, Pod Affinity, và Pod Anti-Affinity.
Phân biệt giữa required vs preferred scheduling.
Biết cách áp dụng vào thực tế để tối ưu hệ thống cho tính sẵn sàng, hiệu năng, và quản lý tài nguyên.
⚙️ 1. Affinity là gì?
Affinity là các ràng buộc (constraints) cho phép bạn điều khiển Scheduler nên (hoặc không nên) đặt Pod ở đâu, gần Pod nào, hoặc trên node có đặc điểm gì.
Có ba loại chính:
Loại | Mô tả |
Node Affinity | Ràng buộc giữa Pod và Node |
Pod Affinity | Ràng buộc giữa Pod và các Pod khác |
Pod Anti-Affinity | Ràng buộc "né tránh" các Pod khác |
Affinity (hay còn gọi là "tính liên kết") là một cơ chế trong Kubernetes cho phép bạn định nghĩa các quy tắc để thu hút các pod tới các node cụ thể dựa trên các thuộc tính như nhãn (labels), vùng (region), hoặc đặc điểm phần cứng. Ví dụ, bạn có thể muốn một số pod chạy trên các node có phần cứng mạnh hơn (như CPU hoặc GPU chuyên dụng) hoặc trong cùng một khu vực địa lý để giảm độ trễ.
Có hai loại affinity chính:
Node Affinity: Quy định pod được triển khai trên các node dựa trên nhãn của node.
Pod Affinity: Quy định pod được triển khai gần các pod khác dựa trên nhãn của chúng, thường để tối ưu hóa giao tiếp mạng hoặc hiệu suất.
Anti-Affinity
Ngược lại, Anti-Affinity (tính "tránh né") đảm bảo các pod không được triển khai trên cùng một node hoặc gần các pod khác, thường được sử dụng để tăng tính sẵn sàng cao (high availability) hoặc phân tán workload. Ví dụ, bạn có thể muốn các bản sao (replicas) của một ứng dụng được chạy trên các node khác nhau để tránh điểm lỗi duy nhất (single point of failure).
Có hai loại anti-affinity:
Node Anti-Affinity: Ngăn pod chạy trên các node cụ thể.
Pod Anti-Affinity: Ngăn pod chạy gần các pod khác có cùng nhãn.
Các vấn đề liên quan đến Affinity và Anti-Affinity
1. Cân bằng giữa hiệu suất và tính sẵn sàng
Một trong những vấn đề lớn nhất khi sử dụng affinity và anti-affinity là tìm ra sự cân bằng giữa hiệu suất và tính sẵn sàng. Ví dụ:
Nếu bạn sử dụng pod affinity để đặt các pod gần nhau trên cùng một node hoặc zone, bạn có thể cải thiện hiệu suất bằng cách giảm độ trễ mạng. Tuy nhiên, điều này làm tăng nguy cơ mất toàn bộ ứng dụng nếu node hoặc zone đó gặp sự cố.
Ngược lại, pod anti-affinity giúp tăng tính sẵn sàng bằng cách phân tán các pod, nhưng có thể dẫn đến độ trễ mạng cao hơn hoặc tăng chi phí vận hành nếu các pod được triển khai trên các vùng địa lý khác nhau.
Giải pháp:
Sử dụng soft affinity/anti-affinity (preferredDuringSchedulingIgnoredDuringExecution) thay vì hard affinity/anti-affinity (requiredDuringSchedulingIgnoredDuringExecution). Điều này cho phép scheduler linh hoạt hơn khi không thể đáp ứng tất cả các yêu cầu.
Kết hợp với Topology Spread Constraints để kiểm soát phân phối pod một cách chi tiết hơn, ví dụ như phân tán đều pod trên các zone hoặc node.
2. Hiệu suất của Scheduler
Việc sử dụng các quy tắc affinity và anti-affinity phức tạp có thể làm tăng tải cho Kubernetes scheduler, đặc biệt trong các cluster lớn với hàng ngàn pod và node. Các quy tắc phức tạp đòi hỏi scheduler phải đánh giá nhiều điều kiện hơn, dẫn đến thời gian lập lịch lâu hơn và có thể gây chậm trễ trong việc triển khai pod.
Giải pháp:
Giới hạn số lượng quy tắc affinity/anti-affinity trong một deployment.
Sử dụng nhãn (labels) và bộ chọn (selectors) một cách cụ thể và hiệu quả để giảm số lượng node hoặc pod cần đánh giá.
Theo dõi hiệu suất của scheduler bằng các công cụ như Prometheus và Grafana để phát hiện các vấn đề tiềm ẩn.
3. Xung đột giữa các quy tắc
Khi có nhiều quy tắc affinity và anti-affinity được áp dụng, chúng có thể mâu thuẫn với nhau. Ví dụ, một quy tắc pod affinity yêu cầu các pod chạy trên cùng node, nhưng một quy tắc pod anti-affinity lại ngăn các pod đó chạy cùng nhau. Điều này có thể khiến scheduler không thể tìm ra vị trí hợp lệ để triển khai pod.
Giải pháp:
Kiểm tra và xác nhận các quy tắc trước khi áp dụng bằng cách sử dụng công cụ như kubectl describe hoặc kubectl explain.
Sử dụng các công cụ như Kubeval hoặc Kube-linter để phân tích cấu hình YAML và phát hiện các xung đột tiềm ẩn.
4. Quản lý tài nguyên không đồng đều
Sử dụng node affinity để triển khai pod trên các node có phần cứng đặc biệt (như GPU) có thể dẫn đến việc sử dụng tài nguyên không đồng đều trong cluster. Một số node có thể bị quá tải, trong khi các node khác lại nhàn rỗi.
Giải pháp:
Kết hợp affinity với resource requests và limits để đảm bảo pod không tiêu tốn quá nhiều tài nguyên trên một node.
Sử dụng Horizontal Pod Autoscaler (HPA) và Cluster Autoscaler để tự động mở rộng hoặc thu hẹp tài nguyên dựa trên nhu cầu.
5. Khả năng mở rộng và chi phí
Việc sử dụng anti-affinity để phân tán pod trên nhiều node hoặc zone có thể làm tăng chi phí, đặc biệt trong môi trường cloud nơi bạn phải trả tiền cho mỗi node hoặc vùng. Ngoài ra, trong các cluster nhỏ, việc áp dụng anti-affinity nghiêm ngặt có thể không khả thi do số lượng node hạn chế.
Giải pháp:
Đánh giá cẩn thận chi phí và lợi ích của việc phân tán pod.
Sử dụng taints và tolerations để kiểm soát việc triển khai pod trên các node cụ thể thay vì chỉ dựa vào anti-affinity.
Xem xét sử dụng các dịch vụ cloud có giá cả tối ưu, như spot instances, để giảm chi phí.
📦 2. Node Affinity
Dùng để chọn Node theo nhãn (label).
📘 Ví dụ:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
✅ Use case: Chạy Pod trên các node có SSD, hoặc thuộc nhóm "high-performance".
🔗 3. Pod Affinity – Gắn bó cùng nhau
Cho phép bạn đặt Pod gần Pod khác, thường dùng khi các Pod cần trao đổi dữ liệu nhanh, chia sẻ volume, hoặc co-location để giảm latency.
📘 Ví dụ:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: frontend
topologyKey: "kubernetes.io/hostname"
✅ Use case: Đặt Pod frontend
gần Pod backend
.
🚫 4. Pod Anti-Affinity – Né tránh nhau
Cho phép bạn đặt Pod xa các Pod khác, dùng khi cần đảm bảo tính sẵn sàng, hoặc tránh tình trạng "noisy neighbor".
📘 Ví dụ:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: web
topologyKey: "kubernetes.io/hostname"
✅ Use case: Tránh đặt các Pod web
cùng một Node để giảm rủi ro khi Node die.
⚖️ 5. required
vs preferred
: Khi nào dùng cái nào?
Thuộc tính | Hành vi | Rủi ro |
requiredDuringSchedulingIgnoredDuringExecution | Bắt buộc – nếu không thoả, Pod không được lên | Dễ gây pending |
preferredDuringSchedulingIgnoredDuringExecution | Ưu tiên – nếu không thoả, vẫn được lên | Linh hoạt hơn |
👉 Lời khuyên:
Dùng
required
cho các yêu cầu khắt khe (multi-zone, HA).Dùng
preferred
cho tối ưu hóa nhẹ nhàng (co-location, tránh overload).
🚀 6. Use Case Thực Tế
🟢 Case 1: Đảm bảo HA cho Redis Cluster
yamlCopyEditpodAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: redis
topologyKey: "kubernetes.io/hostname"
🔎 Ý nghĩa: Các Redis replica không được nằm cùng node — nếu một node chết, cluster vẫn sống.
🟠 Case 2: Tăng hiệu năng cho Pod frontend + backend
yamlCopyEditpodAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: backend
topologyKey: "kubernetes.io/hostname"
🔎 Ý nghĩa: Pod frontend sẽ cố gắng chạy cùng node với backend để tối ưu latency.
🔍 7. Các lỗi thường gặp
Vấn đề | Nguyên nhân | Cách khắc phục |
Pod không lên | required quá chặt, không node nào thỏa | Dùng preferred hoặc nới điều kiện |
Không phân tán đều | Dùng sai topologyKey | Dùng kubernetes.io/hostname hoặc topology.kubernetes.io/zone |
Scheduler xử lý chậm | Nhiều ràng buộc phức tạp | Giảm weight , tối ưu rule |
✅ 8. Kết luận
Hiểu và áp dụng đúng Affinity & Anti-Affinity giúp bạn:
Tăng tính sẵn sàng cho hệ thống.
Tối ưu tài nguyên và giảm rủi ro khi node fail.
Tăng hiệu suất khi cần co-location.
Khi thiết kế, hãy luôn nghĩ đến:
Kịch bản xấu nhất (node fail).
Tài nguyên thực tế của cluster.
Cân bằng giữa tính khả thi và kỳ vọng logic.
Subscribe to my newsletter
Read articles from Kilo directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
