Zoom-in: Load Balancer

Một domain. Hàng triệu request mỗi ngày. Không server nào xử lý được một mình — và ngay cả khi có thể, một server duy nhất là một điểm thất bại duy nhất.
Phóng to dần vào cách traffic được phân phối.
Layer 1 — Vấn đề: single point of failure
Không có load balancer, mọi request đều đến một server.
graph LR
U1["👤 User 1"] -->|"request"| S["🖥️ Server"]
U2["👤 User 2"] -->|"request"| S
U3["👤 User 3"] -->|"request"| S
S -.->|"💥 down"| X[" "]
style U1 fill:#1e3a5f,stroke:#3b82f6,color:#93c5fd
style U2 fill:#1e3a5f,stroke:#3b82f6,color:#93c5fd
style U3 fill:#1e3a5f,stroke:#3b82f6,color:#93c5fd
style S fill:#7f1d1d,stroke:#ef4444,color:#fca5a5
Server xuống → toàn bộ service xuống. Deploy mới → downtime. Spike traffic → server quá tải. Load balancer giải quyết cả ba bằng cách đứng trước nhiều server và phân phối request.
Layer 2 — Thuật toán phân phối
Ba thuật toán phổ biến, ba trade-off khác nhau.
graph TD
LB["⚖️ Load Balancer"]
LB -->|"Round-robin: lần lượt"| S1["🖥️ Server 1"]
LB -->|"Round-robin: lần lượt"| S2["🖥️ Server 2"]
LB -->|"Round-robin: lần lượt"| S3["🖥️ Server 3"]
style LB fill:#3b2a1a,stroke:#f59e0b,color:#fcd34d
style S1 fill:#1a3a2a,stroke:#22c55e,color:#86efac
style S2 fill:#1a3a2a,stroke:#22c55e,color:#86efac
style S3 fill:#1a3a2a,stroke:#22c55e,color:#86efac
Round-robin: mỗi request lần lượt đến server tiếp theo. Đơn giản, không cần trạng thái. Nhược điểm: không tính đến việc server 1 đang xử lý request nặng trong khi server 2 rảnh.
Least connections: request đến server đang có ít kết nối nhất. Phù hợp khi request có thời gian xử lý không đồng đều — ví dụ, một số query DB chạy lâu hơn nhiều.
IP hash: IP của client xác định server nhận request. Cùng một client luôn đến cùng một server — dùng khi cần session affinity mà không muốn dùng sticky sessions ở tầng LB.
Layer 3 — Health check: chỉ gửi đến server còn sống
Load balancer định kỳ kiểm tra từng server backend.
sequenceDiagram
participant LB as ⚖️ Load Balancer
participant S1 as 🖥️ Server 1 (healthy)
participant S2 as 🖥️ Server 2 (down)
loop Mỗi 10 giây
LB->>S1: GET /health
S1-->>LB: 200 OK
LB->>S2: GET /health
Note over S2: timeout
LB->>S2: GET /health (retry)
Note over S2: timeout lần 2
Note over LB: Đánh dấu S2 unhealthy
end
Note over LB: Chỉ gửi traffic đến S1
Health check có thể là TCP ping (chỉ kiểm tra port mở) hoặc HTTP request đến /health endpoint (kiểm tra app thật sự phản hồi được). HTTP health check chính xác hơn — server có thể nghe được TCP nhưng app bên trong đã crash.
Khi server hồi phục, load balancer sau vài lần health check thành công sẽ tự động đưa server trở lại pool.
Layer 4 — L4 vs L7: hai tầng, hai khả năng
graph LR
subgraph "Layer 4 LB (TCP)"
LB4["⚖️ L4 LB"] -->|"dựa trên IP:port"| S4A["🖥️ Server A"]
LB4 -->|"dựa trên IP:port"| S4B["🖥️ Server B"]
end
subgraph "Layer 7 LB (HTTP)"
LB7["⚖️ L7 LB"] -->|"/api/* → API server"| SA["🖥️ API Server"]
LB7 -->|"/static/* → CDN origin"| SB["🖥️ Static Server"]
LB7 -->|"Host: admin.* → admin"| SC["🖥️ Admin Server"]
end
style LB4 fill:#3b2a1a,stroke:#f59e0b,color:#fcd34d
style LB7 fill:#3b2a1a,stroke:#f59e0b,color:#fcd34d
style S4A fill:#1a3a2a,stroke:#22c55e,color:#86efac
style S4B fill:#1a3a2a,stroke:#22c55e,color:#86efac
style SA fill:#1a3a2a,stroke:#22c55e,color:#86efac
style SB fill:#1a3a2a,stroke:#22c55e,color:#86efac
style SC fill:#1a3a2a,stroke:#22c55e,color:#86efac
L4 load balancer (AWS NLB, HAProxy TCP mode): hoạt động ở tầng transport. Nhanh, ít overhead, nhưng chỉ thấy IP và port — không thể route theo URL path hay HTTP header.
L7 load balancer (AWS ALB, nginx, Traefik): hoạt động ở tầng application. Đọc được HTTP header, URL, cookie — cho phép route theo content. Có thể terminate TLS, thêm header, thực hiện A/B testing, rate limit theo path.
Hầu hết web service dùng L7 vì flexibility. L4 phù hợp khi cần latency cực thấp hoặc protocol không phải HTTP.
Layer 5 — Sticky sessions: gắn user vào server
Đôi khi cần đảm bảo cùng một user luôn đến cùng một server.
sequenceDiagram
participant U as 👤 User
participant LB as ⚖️ L7 Load Balancer
participant S1 as 🖥️ Server 1
participant S2 as 🖥️ Server 2
U->>LB: Request lần đầu
LB->>S1: Forward request
S1-->>LB: Response + Set-Cookie: SERVERID=s1
LB-->>U: Response + cookie
U->>LB: Request lần 2 (cookie: SERVERID=s1)
Note over LB: Cookie → route đến S1
LB->>S1: Forward request
S1-->>U: Response
Sticky sessions giải quyết bài toán stateful session — nhưng tạo ra vấn đề mới: nếu S1 xuống, tất cả session gắn vào S1 bị mất. Giải pháp tốt hơn là externalize state ra Redis hoặc DB — server nào cũng đọc được session của user, không cần sticky.
Full picture
graph TD
U1["👤 Users"] -->|"requests"| LB
subgraph "Load Balancer"
LB["⚖️ L7 LB\n(nginx / ALB)"]
LB --> HC["🔍 Health Check\n(mỗi 10s)"]
end
LB -->|"round-robin / least-conn"| S1["🖥️ Server 1\n✓ healthy"]
LB -->|"round-robin / least-conn"| S2["🖥️ Server 2\n✓ healthy"]
LB -.->|"🚫 bỏ qua"| S3["🖥️ Server 3\n✗ unhealthy"]
S1 & S2 --> DB[("💾 Shared DB\n+ Redis")]
style LB fill:#3b2a1a,stroke:#f59e0b,color:#fcd34d
style S1 fill:#1a3a2a,stroke:#22c55e,color:#86efac
style S2 fill:#1a3a2a,stroke:#22c55e,color:#86efac
style S3 fill:#7f1d1d,stroke:#ef4444,color:#fca5a5
style DB fill:#1e3a5f,stroke:#3b82f6,color:#93c5fd
Takeaway
Load balancer không chỉ là "chia đều request". Nó là điểm quyết định: server nào còn sống, request nào đến đâu, session được xử lý thế nào. Chọn L4 hay L7 là lựa chọn kiến trúc — không chỉ là config.
Stateful session là nguyên nhân phổ biến nhất khiến horizontal scaling trở nên khó: hai request liên tiếp của cùng user có thể đến hai server khác nhau. Externalize state ra shared storage là điều kiện để load balancer hoạt động đúng nghĩa.
Bài viết được hỗ trợ bởi Amy 🌸 - AI Assistant. Nội dung đã được kiểm duyệt bởi tác giả.
Related Posts
Zoom-in: TCP
Mọi HTTP request đều đi trên TCP — nhưng trước khi byte đầu tiên của dữ liệu đi qua, đã có 3 gói tin trao đổi mà không mang dữ liệu nào. TCP giải quyết vấn đề mà Internet không giải quyết được.
Zoom-in: DNS
Gõ 'google.com', nhấn Enter. Máy tính không hiểu tên miền — nó chỉ hiểu địa chỉ IP. Giữa hai thứ đó là một hệ thống phân tán với 4 tầng tra cứu.
Zoom-in: HTTP
Mọi ứng dụng web đều bắt đầu từ một mô hình đơn giản: client hỏi, server trả lời. HTTP là ngôn ngữ của cuộc hội thoại đó.