Load balancer là gì và tại sao cần
Khi có nhiều instance/Pod phục vụ cùng service, cần thành phần phân phối request, đó là Load Balancer:
Client
│
▼
Load Balancer 1.2.3.4:443
│
├──► App instance 1 10.0.2.10:8080
├──► App instance 2 10.0.2.11:8080
└──► App instance 3 10.0.2.12:8080LB đảm bảo:
- Không có SPOF (single point of failure) ở tầng app.
- Scale out: thêm/xóa instance mà client không biết.
- Health checking: tự loại instance bị lỗi khỏi pool.
L4 vs L7 Load Balancer
| L4 (TCP/UDP) | L7 (HTTP/HTTPS) | |
|---|---|---|
| Nhìn tới tầng | TCP/UDP | HTTP header, URL, cookie |
| TLS | Pass-through hoặc terminate | Thường terminate |
| Routing | Theo IP:port | Theo Host, Path, Header |
| Hiệu suất | Cao hơn (ít xử lý) | Thấp hơn (parse HTTP) |
| Dùng cho | Database proxy, game, streaming | Web API, microservice |
| Ví dụ | AWS NLB, TCP mode HAProxy | AWS ALB, NGINX, Traefik |
Khi nào dùng L4:
- Cần preserve client IP một cách thuần túy.
- Protocol không phải HTTP (MQTT, Redis, PostgreSQL wire protocol).
- Cần throughput cực cao, latency cực thấp.
Khi nào dùng L7:
- HTTP/HTTPS và cần routing theo path/host.
- Cần ghi log chi tiết (URL, method, status code).
- A/B test, canary deploy theo header.
gRPC cần LB biết HTTP/2
Lưu ý quan trọng: gRPC chạy trên HTTP/2, mở một connection rồi ghép nhiều RPC (stream) vào đó và giữ kết nối lâu. Nếu dùng L4 LB (NLB) với chế độ round-robin theo connection, tất cả RPC của một client sẽ đổ vào một backend → mất cân bằng nghiêm trọng khi có ít client nhưng nhiều RPC.
Giải pháp:
- L7 LB biết HTTP/2 (Envoy, NGINX với
grpc_pass, ALB hỗ trợ gRPC, Istio, Linkerd), load balance theo stream/request không theo connection. - Hoặc client-side load balancing với service discovery (gRPC-LB, xDS từ Envoy).
- Trên Kubernetes: Service
ClusterIP+ iptables load balance theo connection → gRPC cũng lệch tải; dùng headless Service + DNS round-robin hoặc service mesh để phân tải theo request.
Gateway API, thay thế Ingress ở L7
Với K8s production mới, cân nhắc Gateway API (xem bài 10) thay vì Ingress annotation vendor: tách vai trò platform (Gateway) khỏi team app (HTTPRoute), hỗ trợ weighted routing, gRPC, TCP native. Controller điển hình: Envoy Gateway, Istio, NGINX Gateway Fabric, Cilium.
Thuật toán phân tải
| Thuật toán | Cách hoạt động | Phù hợp |
|---|---|---|
| Round Robin | Lần lượt theo thứ tự | Request xử lý nhanh, đồng đều |
| Least Connections | Gửi tới instance ít connection nhất | Request xử lý lâu, khác nhau |
| IP Hash | Hash IP client → instance cố định | Session affinity |
| Weighted | Phân theo trọng số | Canary (10% traffic mới) |
Health check, trái tim của LB
LB định kỳ probe từng instance. Nếu fail → loại khỏi pool; khi OK lại → thêm vào pool.
Load Balancer
│ (probe mỗi ~10s)
├──► Instance A GET /health → 200 OK
└──► Instance B GET /health → 503Cấu hình health check quan trọng
| Tham số | Ý nghĩa | Giá trị điển hình |
|---|---|---|
| Path | Endpoint probe (HTTP) | /health, /ready, /ping |
| Interval | Tần suất probe | 10–30s |
| Timeout | Thời gian chờ response | 5s |
| Healthy threshold | Số lần OK liên tiếp để vào pool | 2–3 |
| Unhealthy threshold | Số lần fail để loại khỏi pool | 2–3 |
Health check endpoint tốt
GET /health → 200 OK
{
"status": "ok",
"db": "ok",
"cache": "ok"
}
GET /health → 503 Service Unavailable (khi DB không reach được)
Không dùng endpoint phức tạp (query DB nặng) làm health check, gây quá tải khi LB probe liên tục.
Phân biệt /health vs /ready:
/health(liveness): app còn sống không? Nếu fail → restart pod (K8s)./ready(readiness): app sẵn sàng nhận traffic không? Nếu fail → không gửi traffic, nhưng không restart.
Connection draining / deregistration delay
Khi LB remove một instance (deploy mới, scale down):
[1] Không có draining
│
▼
[2] LB đóng connection ngay → #pink:50 request bị cắt — client 502
│
▼
[3] Có connection draining (ví dụ 60s)
│
▼
[4] LB chờ tối đa 60 giây
│
▼
[5] Instance hoàn thành request hiện tại → #lightgreen:ít 502 hơnCấu hình điển hình:
- AWS ALB: “Deregistration delay” = 30–60s.
- Kubernetes:
terminationGracePeriodSeconds+preStophook.
Graceful shutdown trong app
App cũng phải hỗ trợ graceful shutdown để không cắt request giữa chừng:
[SIGTERM nhận được]
1. Dừng nhận request mới (close listening socket hoặc trả 503)
2. Chờ request đang xử lý hoàn thành
3. Đóng kết nối DB / cache
4. Exit 0
Node.js ví dụ:
process.on("SIGTERM", () => {
server.close(() => {
db.disconnect().then(() => process.exit(0));
});
// Force exit nếu quá lâu
setTimeout(() => process.exit(1), 30000);
});
Tóm tắt
- L4 cho TCP/UDP thuần; L7 cho HTTP routing và visibility.
- Health check đúng endpoint và threshold = không có traffic vào instance xấu.
- Connection draining = deploy không 502; không có draining = cắt connection bất ngờ.
- App phải handle SIGTERM gracefully, LB draining và app graceful shutdown phải khớp nhau.
Câu hỏi hay gặp
Health check gọi DB mỗi lần probe, có vấn đề không?
Trả lời: Có thể rất tải DB (30×10×instance = số query/phút). Nên endpoint nhẹ (process sống, file tĩnh) hoặc cached check; DB chỉ khi thật cần và throttle.
terminationGracePeriodSeconds: 30 nhưng request dài nhất 60s, điều gì xảy ra?
Trả lời: Sau 30s kubelet SIGKILL (sau SIGTERM); request có thể bị cắt, client 502/reset. Cần tăng grace period, preStop delay, hoặc drain ở LB trước.
Chỉ có L4 NLB mà muốn tách /api và /admin, làm được không?
Trả lời: L4 không đọc path HTTP. Cần L7 (ALB, Ingress NGINX, HAProxy HTTP mode) hoặc hai listener/port khác nhau nếu tách bằng cổng.
Bài tiếp theo (Giai đoạn IV): TLS tự động trong cluster với cert-manager, tự động hóa vòng đời chứng chỉ để không bao giờ bị hết hạn bất ngờ.