Giao diện
Load Balancing — Phân phối tải thông minh
Tháng 10/2021, Facebook sập toàn cầu trong 6 giờ. Nguyên nhân gốc rễ: một thay đổi cấu hình BGP khiến DNS servers không thể truy cập — nhưng điều khiến sự cố kéo dài là hệ thống load balancing mất khả năng route traffic về đúng nơi. Khi load balancer sập, toàn bộ hạ tầng phía sau trở nên vô hình với thế giới bên ngoài.
Load balancer là "bộ não điều phối" của mọi hệ thống production. Nó quyết định request nào đi đến server nào, phát hiện server chết, và cho phép bạn deploy code mới mà không ai nhận ra. Hiểu sâu về load balancing không chỉ là chọn giữa round-robin hay least-connections — mà là hiểu cách thiết kế hệ thống zero-downtime và tránh cascading failures.
Bức tranh tư duy
Hãy tưởng tượng một bến xe buýt lớn ở Sài Gòn giờ cao điểm.
Nếu tất cả hành khách xếp vào một cửa duy nhất, xe nào đến trước lấy hết khách — có xe chật cứng, có xe chạy không. Một điều phối viên thông minh (load balancer) sẽ đứng giữa: nhìn xe nào còn ghế trống, xe nào sắp xuất bến, hành khách nào cần đi tuyến nào, rồi phân luồng.
Điều phối viên L4 chỉ nhìn biển số xe và số ghế (IP:Port) — nhanh nhưng không thông minh. Điều phối viên L7 nhìn được tuyến đường, loại hành khách, và cả hành lý (HTTP headers, URL) — chậm hơn nhưng phân luồng chính xác hơn nhiều.
Analogy này bị giới hạn ở điểm: trong thực tế, load balancer xử lý hàng triệu "hành khách" mỗi giây và quyết định trong microseconds, không phải giây.
Cốt lõi kỹ thuật
L4 vs L7 Load Balancing
| Tiêu chí | L4 (Transport Layer) | L7 (Application Layer) |
|---|---|---|
| Hoạt động tại | TCP/UDP — chỉ thấy IP:Port | HTTP/HTTPS — thấy URL, headers, cookies |
| Throughput | 10M+ connections/s | 100K-1M requests/s |
| Latency overhead | ~10-50μs | ~100-500μs |
| Content routing | ❌ Không thể | ✅ Route theo URL, header, cookie |
| SSL termination | ❌ Pass-through | ✅ Decrypt tại LB |
| WebSocket support | ✅ Transparent | ✅ Nhưng cần cấu hình |
| Use case | Edge LB, high throughput | Intelligent routing, API gateway |
Production pattern chuẩn: L4 LB ở edge (IPVS, Maglev, NLB) chịu tải cao → route đến cluster L7 LB (Nginx, Envoy, ALB) để xử lý intelligent routing. Không bao giờ để L7 LB chịu internet traffic trực tiếp.
Thuật toán Load Balancing
1. Round Robin — Đơn giản, phân bổ tuần tự
Request: R1 R2 R3 R4 R5 R6
Server A: R1 R4
Server B: R2 R5
Server C: R3 R6Ưu điểm: Zero state, dễ implement. Nhược điểm: Giả định mọi server có capacity bằng nhau và mọi request có cost bằng nhau — hiếm khi đúng trong thực tế.
2. Weighted Round Robin — Phân bổ theo trọng số
Server A (weight=5): nhận 50% traffic
Server B (weight=3): nhận 30% traffic
Server C (weight=2): nhận 20% trafficHữu ích khi servers có cấu hình khác nhau (canary deployment: server mới nhận 10% traffic để test).
3. Least Connections — Gửi đến server rảnh nhất
Server A: ████████████ (12 connections)
Server B: ████████ (8 connections) ◄── SEND HERE
Server C: ████████████████ (16 connections)Tốt cho long-lived connections (WebSocket, database proxying) vì nó tự điều chỉnh theo load thực tế.
4. IP Hash — Cùng client, cùng server
hash("192.168.1.100") % 3 = 1 → Server B
hash("10.0.0.50") % 3 = 0 → Server AĐảm bảo session affinity mà không cần shared session store. Nhưng có nhược điểm lớn — xem phần Sai lầm điển hình.
5. Consistent Hashing — Thuật toán tỷ đô
Khi dùng hash(key) % N, thêm 1 server khiến ~75% keys phải remap. Consistent hashing giải quyết vấn đề này.
Thêm server D tại 80°: chỉ keys trong range [45°, 80°] remap sang D. Tất cả keys khác không đổi.
Virtual Nodes: Mỗi physical server được map thành 100-200 virtual nodes trên ring để đảm bảo phân bố đều. Không có virtual nodes, 3 server có thể phân bố cực kỳ lệch — một server handle 70% traffic.
Health Checks
Health check là cách load balancer phát hiện server chết và ngừng gửi traffic đến đó.
| Loại | Cơ chế | Tốc độ phát hiện | Độ chính xác |
|---|---|---|---|
| TCP check | Mở TCP connection | Nhanh (~1s) | Thấp (port mở ≠ app healthy) |
| HTTP check | GET /health → 200 OK | Trung bình (~3s) | Cao (kiểm tra app logic) |
| Deep check | GET /health/deep → check DB, Redis | Chậm (~5s) | Rất cao (kiểm tra dependencies) |
Best practice: Dùng HTTP health check cho load balancer routing, deep check cho monitoring/alerting. Tránh dùng deep check cho LB routing vì dependency failure (DB chậm) sẽ đánh sập tất cả servers cùng lúc.
So sánh Load Balancer phổ biến
| LB | Loại | Điểm mạnh | Điểm yếu | Dùng khi |
|---|---|---|---|---|
| HAProxy | Software L4/L7 | Performance cao, config linh hoạt | Không có dashboard đẹp sẵn | On-premise, high throughput |
| Nginx | Software L7 | Static serving + LB, ecosystem lớn | L4 performance kém hơn HAProxy | Web server kiêm LB |
| AWS ALB | Cloud L7 | Managed, auto-scale, WAF integration | Vendor lock-in, cost tăng theo traffic | AWS workloads |
| AWS NLB | Cloud L4 | Cực nhanh, static IP | Không content routing | High throughput trên AWS |
| Envoy | Sidecar L7 | Observability, gRPC native | Learning curve cao | Service mesh, Kubernetes |
Thực chiến
Tình huống: Zero-Downtime Deployment
Bối cảnh: E-commerce platform, 5000 RPS, deploy code mới 3 lần/ngày. Không thể chấp nhận downtime — mỗi giây mất $50 revenue.
Mục tiêu: Deploy version mới mà không drop một request nào.
Rolling deployment với LB:
Connection Draining (Graceful Shutdown):
- LB ngừng gửi request mới đến server
- Server hoàn thành tất cả in-flight requests (timeout 30-60s)
- Server shutdown
- Deploy version mới, start lại
- Health check pass → LB bắt đầu gửi traffic
Phân tích: Với 3 servers, mỗi lúc chỉ 2 servers active → mỗi server chịu thêm 50% load. Phải đảm bảo 2 servers handle được toàn bộ peak traffic.
Tình huống: Canary Deployment với Weighted Routing
Bối cảnh: Deploy feature mới có risk cao (thay đổi payment flow). Cần test với lượng nhỏ traffic trước.
Chiến lược:
Phase 1: Route 5% traffic → v2 (canary), 95% → v1
Phase 2: Monitor error rate, latency 30 phút
Phase 3: Nếu OK → tăng lên 25% → 50% → 100%
Phase 3 (alt): Nếu lỗi → rollback 100% về v1 trong < 1 phútNginx config ví dụ:
nginx
upstream backend {
server 10.0.1.1 weight=95; # v1 - stable
server 10.0.1.2 weight=5; # v2 - canary
}Sai lầm điển hình
❌ Sai lầm 1: Sticky Sessions phá vỡ Horizontal Scaling
Vấn đề: Dùng sticky sessions (IP hash hoặc cookie-based) để giữ session — kết quả: một số server quá tải vì "hot users", và không thể scale đều.
Tại sao sai: Sticky sessions biến horizontal scaling thành vertical scaling trá hình. Khi server A chết, tất cả users sticky vào A mất session. Khi traffic không đều (một số users active hơn), load imbalance nghiêm trọng.
Đúng: Externalize session ra Redis/Memcached. Mọi server đều stateless, bất kỳ server nào cũng handle được bất kỳ request nào. Dùng JWT cho stateless auth khi có thể.
❌ Sai lầm 2: Không implement Health Checks
Vấn đề: Load balancer gửi traffic đến server đã chết hoặc đang overloaded → user nhận 502/503.
Tại sao hay mắc: Team setup LB và quên config health check, hoặc health check endpoint chỉ return 200 OK mà không kiểm tra gì thực sự.
Đúng: Implement /health endpoint kiểm tra app readiness (database connection, critical service dependencies). Config LB với health check interval 5-10s, unhealthy threshold 3 lần liên tiếp.
❌ Sai lầm 3: Single Load Balancer — Single Point of Failure
Vấn đề: Một load balancer duy nhất trước toàn bộ hệ thống. LB chết = toàn bộ hệ thống chết.
Tại sao sai: Load balancer supposed to tăng reliability, nhưng single LB lại tạo SPOF mới. Ironic.
Đúng: Deploy LB cluster với active-passive hoặc active-active setup. Dùng DNS-based failover hoặc floating IP (VRRP/keepalived) để tự động chuyển traffic khi primary LB chết.
❌ Sai lầm 4: Không implement Connection Draining
Vấn đề: Server bị remove khỏi LB pool → in-flight requests bị drop → user thấy lỗi.
Tại sao sai: Đặc biệt nghiêm trọng với long-lived connections (WebSocket, file upload, streaming). Một upload 500MB bị abort ở 99% vì server bị yank khỏi pool.
Đúng: Luôn config connection draining timeout (30-60s) trên LB. Server nhận SIGTERM → ngừng accept request mới → hoàn thành in-flight → shutdown.
Under the Hood
Consistent Hashing ngăn chặn Cascading Failures
Khi một server trong consistent hashing ring chết, chỉ load của server đó được redistribute sang server kế tiếp trên ring. Với virtual nodes, load này được phân tán đều cho nhiều servers.
So sánh với hash % N: khi 1 server chết (N → N-1), tất cả keys bị remap → cache stampede → cascading failure.
Toán học: Với consistent hashing và K virtual nodes/server:
- Thêm/bớt 1 server → chỉ K/(N×K) = 1/N keys cần remap
- Với 10 servers: chỉ ~10% keys di chuyển (thay vì ~90% với mod hashing)
Thundering Herd khi LB Failure
Khi primary LB fail và secondary LB nhận toàn bộ traffic:
- Tất cả TCP connections phải re-establish (SYN flood)
- TLS handshake cho mỗi connection (CPU spike)
- Health check storm — secondary LB check tất cả backends cùng lúc
- Connection pool exhaustion trên backends
Mitigation: Connection keepalive, TLS session resumption, staggered health checks, pre-warming secondary LB.
Latency Budget Analysis
Theo Jeff Dean's "Numbers Every Programmer Should Know" (ước lượng cập nhật):
| Operation | Latency |
|---|---|
| L1 cache reference | ~1 ns |
| L7 LB processing | ~100-500 μs |
| L4 LB processing | ~10-50 μs |
| Round trip within datacenter | ~500 μs |
| Round trip cross-region | ~50-150 ms |
Nếu SLA yêu cầu P99 < 200ms và cross-region RTT đã 100ms, LB processing budget chỉ còn ~100ms cho app logic. Mỗi microsecond ở LB layer đều quan trọng khi traffic cao.
Trade-offs
| Quyết định | Khi NÊN | Khi KHÔNG NÊN |
|---|---|---|
| L4 LB | Edge, >1M conn/s, raw throughput | Cần content-based routing |
| L7 LB | API routing, canary deploy, A/B test | Ultra-low latency requirements |
| Sticky sessions | Legacy stateful apps (tạm thời) | Mọi trường hợp khác |
| Consistent hashing | Distributed cache, stateful routing | Simple stateless services |
| Active-Active LB | High availability requirement | Budget constraint, low traffic |
Checklist ghi nhớ
✅ Checklist triển khai
Architecture
- [ ] Deploy LB cluster (không single LB) với failover mechanism
- [ ] L4 LB ở edge → L7 LB cluster cho intelligent routing
- [ ] Chọn thuật toán LB phù hợp: least-connections cho hầu hết web apps
Health Checks
- [ ] HTTP health check endpoint
/healthkiểm tra app readiness - [ ] Health check interval 5-10s, unhealthy threshold 3 lần
- [ ] Tách shallow health check (cho LB) và deep health check (cho monitoring)
Deployment
- [ ] Connection draining timeout 30-60s cho mọi deployment
- [ ] Rolling deployment: đảm bảo N-1 servers handle được peak traffic
- [ ] Canary deployment cho high-risk changes
- [ ] Graceful shutdown: SIGTERM → stop accepting → finish in-flight → exit
Performance
- [ ] SSL termination tại LB layer (offload từ app servers)
- [ ] Keep-alive connections giữa LB và backends
- [ ] Monitor LB metrics: active connections, error rate, latency P99
Bài tập luyện tập
Bài 1: Chọn thuật toán LB — Foundation
Đề bài: Cho 4 scenarios, chọn thuật toán load balancing phù hợp nhất:
- Scenario A: API gateway cho microservices, mỗi request độc lập, servers cùng cấu hình
- Scenario B: WebSocket chat server, cần route cùng user về cùng server
- Scenario C: Distributed Redis cache cluster
- Scenario D: Canary deployment, 95% traffic đến v1, 5% đến v2
🧠 Quiz
Câu hỏi: Thuật toán nào phù hợp nhất cho Scenario C (distributed cache cluster)?
- [ ] A. Round Robin
- [ ] B. Least Connections
- [x] C. Consistent Hashing
- [ ] D. Weighted Round Robin Giải thích: Distributed cache cần key-based routing ổn định. Consistent hashing đảm bảo cùng key luôn đến cùng node, và khi thêm/bớt node chỉ ~1/N keys cần remap — tránh cache stampede.
Bài 2: Thiết kế LB cho High Availability — Intermediate
Đề bài: Thiết kế load balancing architecture cho payment service xử lý 10,000 TPS. Yêu cầu:
- Zero single point of failure
- P99 latency < 100ms
- Zero-downtime deployment
- Audit logging cho mọi transaction
Vẽ architecture diagram và giải thích mỗi quyết định.
💡 Gợi ý
- Payment cần L7 cho content inspection
- Dual LB với failover cho HA
- Connection draining cho zero-downtime
- Audit logging tại LB layer hay app layer?
✅ Lời giải
Architecture: DNS → L4 NLB (active-active, 2 nodes) → L7 ALB (2 nodes, cross-zone) → App Servers (min 6, across 3 AZ)
Quyết định thiết kế:
- L4 + L7 combo: L4 cho throughput, L7 cho content routing và TLS termination
- Active-active LB: Cả 2 LB nodes nhận traffic → không có idle capacity
- Cross-zone: Traffic phân bố đều giữa 3 AZ
- 6 app servers: 10K TPS ÷ 2K TPS/server = 5 servers + 1 buffer. Khi rolling deploy (1 server down), 5 servers vẫn handle peak
- Audit logging: Tại app layer (không phải LB) — cần business context
Latency budget: L4 (~30μs) + L7 (~300μs) + App logic (~50ms) + DB (~20ms) = ~70ms < 100ms SLA ✅
Bài 3: Troubleshoot LB Issues — Advanced
Đề bài: Production incident report:
- 2% requests trả về 502 Bad Gateway
- Chỉ xảy ra lúc 2:00 AM (deployment window)
- Health checks vẫn pass
- Backend logs không có error tương ứng
Phân tích 3 nguyên nhân có thể và đề xuất fix cho mỗi nguyên nhân.
💡 Gợi ý
- 502 = LB không kết nối được đến backend
- 2:00 AM = deployment time
- Health check pass nhưng vẫn 502 → timing issue
- Backend không log error → connection rejected trước khi đến app
✅ Lời giải
Nguyên nhân 1: Không có connection draining — server bị kill giữa lúc xử lý request → LB nhận connection reset → trả 502. Fix: Config connection draining 30s, graceful shutdown.
Nguyên nhân 2: Health check interval quá dài — server đã shutdown nhưng LB chưa biết (stale health status). Fix: Giảm health check interval từ 30s xuống 5s, giảm unhealthy threshold.
Nguyên nhân 3: Race condition giữa deregister và new request — LB gửi request đến server đang trong quá trình shutdown. Fix: Deregister server khỏi LB → chờ drain → rồi mới shutdown process.
🎮 Caselet: Real-time multiplayer game — Khi mỗi millisecond đều quan trọng
Hãy tưởng tượng bạn là infrastructure architect cho một tựa game battle royale (tương tự Fortnite hay PUBG). Mỗi trận đấu có 100 người chơi cùng lúc trên một bản đồ, và mọi hành động — di chuyển, bắn, xây công trình — đều phải đồng bộ giữa tất cả player trong vòng vài chục millisecond. Game server cluster của bạn chạy ở tick rate 20-60 ticks/giây cho mỗi player, nghĩa là mỗi trận đấu tạo ra 2,000–6,000 packets/giây. Ở quy mô 1,000 trận đồng thời, hệ thống cần xử lý hàng triệu packets mỗi giây — và bất kỳ độ trễ nào thêm vào đều khiến trải nghiệm trở nên "laggy".
Nhưng game không chỉ có game traffic. Hệ thống bao gồm nhiều service rất khác nhau: matchmaking service (HTTP-based) nhận request từ player, phân tích skill rating và region để ghép trận; game session servers (UDP-based) xử lý game state real-time; và voice chat (WebRTC với TURN servers) cho phép player giao tiếp trong trận. Mỗi service có đặc tính traffic hoàn toàn khác nhau — và đây là insight quan trọng: cùng một ứng dụng nhưng cần các chiến lược load balancing khác nhau.
Với game traffic (UDP), bạn cần L4 load balancer — không có overhead parse HTTP headers, latency thêm vào chỉ ~30 microsecond thay vì hàng trăm microsecond ở L7. Mỗi player phải gắn chặt với một game server suốt trận đấu (sticky sessions), vì game state chỉ tồn tại trên server đó. Nếu LB chuyển player sang server khác giữa chừng, player sẽ bị "teleport" về vị trí mặc định — trải nghiệm thảm họa. Ngược lại, matchmaking API (HTTP) hoàn toàn phù hợp với L7 load balancer — bạn có thể route theo player region (Asia → Singapore servers, EU → Frankfurt servers) hoặc theo game mode, tận dụng header inspection để implement rate limiting cho anti-cheat.
Health check cho game servers phải cực kỳ aggressive: interval 1-2 giây thay vì 10-30 giây thông thường. Game servers chạy ở mức CPU/memory rất cao và có thể crash đột ngột khi một trận đấu có quá nhiều explosions cùng lúc. Nếu health check interval là 30 giây, nghĩa là có thể 30 giây × 60 ticks × 100 players = 180,000 packets bị mất trước khi LB phát hiện server chết. Đó là 30 giây mà 100 người chơi nhìn màn hình đơ cứng.
Voice chat lại là câu chuyện khác. WebRTC traffic đi qua TURN servers, và LB strategy ở đây cần geographic proximity — route player đến TURN server gần nhất để giảm latency cho voice. Đây không phải round-robin hay least-connections, mà là latency-based routing — một dạng LB algorithm mà chỉ các managed services như AWS Global Accelerator hay Cloudflare mới cung cấp hiệu quả.
Câu hỏi trade-off cho bạn: Nếu bạn chỉ được dùng MỘT loại load balancer cho cả game, bạn chọn L4 hay L7? Tại sao? Gợi ý: nghĩ về điều gì xảy ra khi L7 cố xử lý UDP game traffic, và điều gì mất đi khi L4 không thể inspect HTTP headers của matchmaking API.
Bài học cho architect
Không phải lúc nào một hệ thống cũng dùng một loại LB duy nhất. Production systems thường có L4 ở edge và L7 cho từng service riêng biệt. Game architecture là ví dụ điển hình nhất cho multi-tier LB — nơi mỗi tầng giải quyết một bài toán khác nhau: throughput ở edge, intelligent routing ở application layer, và geographic proximity cho real-time communication.
🏗️ Thực hành: Thiết kế LB topology cho flash sale e-commerce
Một sàn thương mại điện tử chuẩn bị cho sự kiện flash sale với 10 triệu người dùng đồng thời. Hệ thống bao gồm:
Các thành phần:
- 🌐 CDN (static assets)
- 🔀 L4 Load Balancer (edge)
- 🔀 L7 Load Balancer (application)
- 🖥️ Web servers (product pages)
- 🛒 Cart service
- 💳 Payment service
- 🗄️ Product database (read replicas)
- 💾 Redis cache cluster
- 📨 Message queue (order processing)
Nhiệm vụ: Sắp xếp các thành phần trên vào đúng vị trí trong kiến trúc, xác định LB algorithm phù hợp cho mỗi tầng.
Internet Traffic (10M users)
│
▼
┌─────────┐
│ [???] │ ← Static assets (CSS, JS, images)
└────┬────┘
│
▼
┌─────────┐
│ [???] │ ← Edge LB — Algorithm: ???
└────┬────┘
│
┌───┴───┐
▼ ▼
┌──────┐ ┌──────┐
│ [???]│ │ [???]│ ← Application LB — Algorithm: ???
└──┬───┘ └──┬───┘
│ │
▼ ▼
┌──────┐ ┌──────┐ ┌──────┐
│ [???]│ │ [???]│ │ [???]│ ← Backend services
└──────┘ └──────┘ └──────┘📋 Đáp án tham khảo
Kiến trúc đề xuất:
- CDN (Cloudflare/CloudFront) → xử lý 70%+ traffic (static assets)
- L4 LB (NLB/IPVS) ở edge → IP hash hoặc round-robin, xử lý TCP connections
- L7 LB (Nginx/Envoy) → route theo URL path:
/products/*→ Web servers (round-robin, cache-friendly)/cart/*→ Cart service (sticky sessions — user phải giữ session)/payment/*→ Payment service (least-connections — tránh overload)
- Web servers → stateless, auto-scale, đọc từ Redis cache + DB read replicas
- Cart service → stateful (session-based), cần sticky sessions
- Payment service → critical path, least-connections + circuit breaker
- Redis cache → consistent hashing cho cache distribution
- Message queue → decouple order processing, absorb traffic spikes
Tại sao architecture này hoạt động:
- CDN giảm 70% load trước khi traffic đến LB
- L4 ở edge: throughput cao, xử lý được 10M connections
- L7 phía trong: intelligent routing cho từng service
- Sticky sessions CHỈ cho cart (cần session state), không cho product pages
- Payment dùng least-connections vì mỗi transaction tốn thời gian khác nhau
Liên kết học tiếp
Từ khóa glossary: Load Balancer, L4/L7, Round Robin, Least Connections, Consistent Hashing, Virtual Nodes, Health Check, Connection Draining, Sticky Sessions, Reverse Proxy, HAProxy, Nginx, Thundering Herd
Tìm kiếm liên quan: phân phối tải, cân bằng tải, reverse proxy, health check, zero-downtime deployment, consistent hashing