Elastic Load Balancing (ELB) là dịch vụ của AWS tự động phân phối traffic đến nhiều targets (EC2 instances, containers, IP addresses, Lambda functions) để đảm bảo high availability và scalability cho ứng dụng.
ALB tạo 2 connections (terminate & re-establish):Client ←──conn 1──→ ALB ←──conn 2──→ Target ↑ ALB terminate connection cũ, tạo connection mới đến targetNLB chỉ forward (pass-through):Client ←─────────────────────────────→ Target ↑ NLB ở giữa, không terminate Forward nguyên packet
Với ALB:Client (1.2.3.4) → ALB (10.0.1.5) → EC2 │ └── EC2 thấy source IP = 10.0.1.5 (IP của ALB) Phải đọc X-Forwarded-For header để lấy IP thậtVới NLB:Client (1.2.3.4) → NLB → EC2 │ └── EC2 thấy source IP = 1.2.3.4 (IP thật của client!)
Vấn đề: Bạn muốn tất cả traffic đi qua firewall trước khi đến app.
Đặt 1 firewall ở trước (không có GWLB): ┌──────────┐Internet ──────▶│ Firewall │──────▶ App └──────────┘ │ ├── Firewall chết = MẤT TOÀN BỘ TRAFFIC! └── Traffic tăng = 1 firewall không xử lý kịp!
Giải pháp: Dùng GWLB để load balance và HA cho firewalls.
Có GWLB (HA + Scale cho firewalls): GWLB (tự động failover) │ ┌───────────┼───────────┐ ▼ ▼ ▼┌────────┐ ┌────────┐ ┌────────┐│Firewall│ │Firewall│ │Firewall││ 1 │ │ 2 │ │ 3 │└────────┘ └────────┘ └────────┘→ Firewall 1 chết? Traffic tự động qua 2 & 3→ Traffic tăng 10x? Thêm firewall instances
Round Robin = Gửi requests lần lượt đến từng target, xoay vòng.
┌─────────────────────────────────────────────────────────────────┐│ ROUND ROBIN ALGORITHM │├─────────────────────────────────────────────────────────────────┤│ ││ Request 1 ──▶ ALB ──▶ Instance A ││ Request 2 ──▶ ALB ──▶ Instance B ││ Request 3 ──▶ ALB ──▶ Instance C ││ Request 4 ──▶ ALB ──▶ Instance A ← Quay lại từ đầu ││ Request 5 ──▶ ALB ──▶ Instance B ││ Request 6 ──▶ ALB ──▶ Instance C ││ ... ││ ││ ✅ Ưu điểm: Đơn giản, dễ hiểu, phân phối đều ││ ❌ Nhược điểm: Không xét đến instance đang bận hay rảnh ││ │└─────────────────────────────────────────────────────────────────┘
Ví dụ thực tế:
Cùng 3 requests, nhưng thời gian xử lý khác nhau:Round Robin:├── Request 1 (nhẹ, 10ms) → Instance A → Done!├── Request 2 (nặng, 5s) → Instance B → Đang xử lý...├── Request 3 (nhẹ, 10ms) → Instance C → Done!├── Request 4 (nhẹ, 10ms) → Instance A → Done!├── Request 5 (nhẹ, 10ms) → Instance B → PHẢI CHỜ! (B đang bận)└── → Instance B bị quá tải dù A và C rảnh
LOR = Gửi request đến instance có ít requests đang chờ xử lý nhất.
┌─────────────────────────────────────────────────────────────────┐│ LEAST OUTSTANDING REQUESTS (LOR) │├─────────────────────────────────────────────────────────────────┤│ ││ Tình huống: Instance B đang xử lý request nặng ││ ││ Instance A: 0 requests đang xử lý ││ Instance B: 3 requests đang xử lý ← Đang bận! ││ Instance C: 1 request đang xử lý ││ ││ LOR quyết định: ││ Request mới ──▶ ALB ──▶ Instance A ← Chọn A (0 outstanding) ││ ││ ✅ Ưu điểm: Thông minh hơn, không gửi đến instance đang bận ││ ✅ Tốt cho: Requests có thời gian xử lý KHÁC NHAU ││ │└─────────────────────────────────────────────────────────────────┘
Flow Hash = Hash dựa trên 5-tuple (Source IP, Source Port, Dest IP, Dest Port, Protocol).
┌─────────────────────────────────────────────────────────────────┐│ FLOW HASH ALGORITHM (NLB) │├─────────────────────────────────────────────────────────────────┤│ ││ 5-tuple = { Source IP, Source Port, Dest IP, Dest Port, Proto }││ ││ Connection từ Client A (1.2.3.4:50123): ││ ┌─────────────────────────────────────────────────────────────┐││ │ Hash(1.2.3.4, 50123, 10.0.1.5, 443, TCP) = 12345 │││ │ 12345 % 3 instances = Instance B │││ └─────────────────────────────────────────────────────────────┘││ ││ → TẤT CẢ packets của connection này đều đến Instance B ││ → Connection ổn định, không bị chuyển instance giữa chừng ││ ││ ✅ Phù hợp: TCP connections dài (database, gaming) ││ ✅ Preserve connection: Cùng flow luôn đến cùng target ││ │└─────────────────────────────────────────────────────────────────┘
Tại sao NLB dùng Flow Hash thay vì Round Robin?
Round Robin KHÔNG phù hợp cho NLB:TCP Connection (nhiều packets):├── Packet 1 (SYN) → Instance A ← Bắt đầu connection├── Packet 2 (SYN-ACK) → Instance B ← LỖI! B không biết connection này!├── Packet 3 (ACK) → Instance C ← LỖI! Connection broken!└── → Connection FAILEDFlow Hash (NLB):├── Packet 1 (SYN) → Instance A ← Bắt đầu connection├── Packet 2 (SYN-ACK) → Instance A ← Cùng instance (same hash)├── Packet 3 (ACK) → Instance A ← Cùng instance├── Packet 4 (Data) → Instance A ← Cùng instance└── → Connection THÀNH CÔNG
Bước 1: Đánh dấu instance "draining" (đang thoát) → KHÔNG gửi requests MỚI đến instance nàyBước 2: Chờ requests CŨ hoàn thành (default 300s)Client A ──────▶ Instance 1 (tiếp tục download... done ✓)Client B ──────▶ Instance 1 (tiếp tục submit... done ✓) Client C ──────▶ Instance 1 (tiếp tục checkout... done ✓)Client D (mới) ──────▶ Instance 2 (requests mới đi instance khác)Bước 3: Sau khi tất cả xong → Remove instance an toàn
Sticky Sessions = Đảm bảo requests từ cùng 1 client luôn được gửi đến cùng 1 target (instance/container).
┌─────────────────────────────────────────────────────────────────┐│ KHÔNG CÓ STICKY SESSIONS │├─────────────────────────────────────────────────────────────────┤│ ││ Client ──▶ Request 1 ──▶ ALB ──▶ Instance A ││ Client ──▶ Request 2 ──▶ ALB ──▶ Instance B ← Khác instance! ││ Client ──▶ Request 3 ──▶ ALB ──▶ Instance C ← Khác nữa! ││ ││ → Mỗi request có thể đến instance khác nhau ││ → Session data (giỏ hàng, login) có thể BỊ MẤT! ││ │├─────────────────────────────────────────────────────────────────┤│ CÓ STICKY SESSIONS │├─────────────────────────────────────────────────────────────────┤│ ││ Client ──▶ Request 1 ──▶ ALB ──▶ Instance A ││ Client ──▶ Request 2 ──▶ ALB ──▶ Instance A ← Cùng instance! ││ Client ──▶ Request 3 ──▶ ALB ──▶ Instance A ← Cùng instance! ││ ││ → Tất cả requests từ client đi đến CÙNG 1 instance ││ → Session data được giữ nguyên ││ │└─────────────────────────────────────────────────────────────────┘
KHUYẾN NGHỊ:├── ❌ Tránh dùng Sticky Sessions nếu có thể├── ✅ Dùng External Session Store (Redis, ElastiCache, DynamoDB) │ → Session được share giữa tất cả instances│ → Client có thể đến bất kỳ instance nào└── ✅ Dùng Stateless Authentication (JWT tokens)
External Session Store (Best Practice):┌──────────┐ ┌──────────┐ ┌──────────┐│Instance A│ │Instance B│ │Instance C│└────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │ └────────────────┼────────────────┘ ▼ ┌──────────────┐ │ Redis │ ← Session được share │ (ElastiCache)│ └──────────────┘→ Client có thể đến bất kỳ instance nào→ Session vẫn đọc được từ Redis→ Instance chết? Không mất session!