API Gateway, Load Balancer, Nginx: ai làm việc gì?
Tiếp đi: API Gateway trong system design.
Bài trước ta nói rate limit nên đặt sớm, ở gateway. Giờ shop-app tách thành microservices: User, Product, Cart, Order, Payment, Inventory. Bài này ở mức kiến trúc; cách cấu hình Spring Cloud Gateway cụ thể đã có ở Spring Cloud Gateway.
1. Bài toán
Mobile App
├── api.shop.com:8081 → User Service
├── api.shop.com:8082 → Order Service
├── api.shop.com:8083 → Payment Service
└── api.shop.com:8084 → Product Service
2. Vấn đề
- Client phải biết service nào ở đâu, port nào; service đổi địa chỉ là phải sửa app.
- Mỗi service tự làm authentication, rate limit, logging, CORS: lặp lại.
- Lộ kiến trúc nội bộ ra Internet.
3. Giải pháp: API Gateway, một cửa vào
Client
│ api.shop.com
▼
┌───────────────┐
│ API Gateway │
└───────┬───────┘
┌──────────────┼──────────────┐
/users/* /orders/* /products/*
▼ ▼ ▼
User Order Product
Capability thường gặp: routing, authentication, rate limiting, TLS termination, request/response transformation, logging, metrics, CORS, API versioning. Không đặt business logic (tính giá, trừ kho) trong gateway.
AuthN ở gateway, AuthZ nghiệp vụ ở service:
- Authentication: "Bạn là ai?". Gateway validate JWT: sai → 401, đúng → chuyển tiếp kèm
user_id. - Authorization: "Bạn được làm gì?". Gateway làm được luật thô (route
/admin/**cần role ADMIN → nếu không có thì 403). Nhưng "user 10 có phải chủ order 123 không?" thì chỉ Order Service có data để biết. Service vẫn phải tự kiểm tra.
BFF (Backend for Frontend): mobile và web cần dữ liệu khác nhau. Thay vì một gateway chung phình to, mỗi loại client có gateway riêng ghép/cắt response phù hợp:
Web → Web BFF ─┐
Mobile → Mobile BFF ─┼─→ Product / Order / Cart services
Partner→ Public API ─┘
4. Code từng bước (tóm tắt)
Bước 1: dependency spring-cloud-starter-gateway-server-webflux + spring-boot-starter-oauth2-resource-server.
Bước 2: route qua service discovery (lb://) và rate limit Redis có sẵn:
spring:
cloud:
gateway:
server:
webflux:
routes:
- id: orders
uri: lb://order-service
predicates: [ Path=/orders/** ]
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 100
key-resolver: "#{@userKeyResolver}"
security:
oauth2:
resourceserver:
jwt:
issuer-uri: ${AUTH_ISSUER_URI}
Bước 3: key resolver theo user đã xác thực:
@Bean
KeyResolver userKeyResolver() {
return exchange -> exchange.getPrincipal()
.map(Principal::getName)
.defaultIfEmpty("anonymous");
}
Bước 4: test.
curl -i https://api.shop.com/orders # 401 (thiếu token)
curl -i -H "Authorization: Bearer $TOKEN" https://api.shop.com/orders # 200
# bắn quá burst → 429
Trong Order Service vẫn kiểm tra quyền sở hữu:
@DeleteMapping("/orders/{id}")
public void cancel(@PathVariable String id, @AuthenticationPrincipal Jwt jwt) {
Order o = orders.get(id);
if (!o.ownerId().equals(jwt.getSubject())) throw new AccessDeniedException("not owner"); // 403
orders.cancel(o);
}
5. Cách hoạt động: request đi qua những tầng nào
Client
│
▼
Cloud LB / Nginx (L4/L7, TLS) ← chịu tải cho chính các gateway instance
│
▼
┌───────────────────┐
│ API Gateway ×N │ Auth → Rate Limit → Routing → Logging
└─────────┬─────────┘
│ "đây là Order API" → lb://order-service
▼
Service Discovery: order-service = [O1, O2, O3] (healthy)
│ load balancing (round robin...)
┌──────┼──────┐
▼ ▼ ▼
O1 O2 O3
Service discovery trả lời "hiện có những instance nào?" (Eureka, hoặc DNS/Service của Kubernetes); load balancer chọn một trong số đó. Instance mới tự đăng ký, instance chết bị loại. Chi tiết: Service discovery.
Sơ đồ trên không bắt buộc. Có hệ thống chỉ có một component vừa làm reverse proxy vừa làm gateway. Phải giải thích được vì sao mỗi tầng tồn tại.
6. So sánh
| API Gateway | Load Balancer | Nginx | |
|---|---|---|---|
| Bản chất | Vai trò/pattern | Vai trò/concept | Một công nghệ cụ thể |
| Câu hỏi chính | Request cần service nào? Có được phép không? | Đi instance nào? | Có thể làm cả hai, tùy cấu hình |
| Việc điển hình | Auth, rate limit, routing theo API, transform, versioning | Phân phối traffic, health check | Reverse proxy, LB, TLS, cache, static file, rate limit |
| Ví dụ | Spring Cloud Gateway, Kong, AWS API Gateway | AWS ALB/NLB, Azure LB | Nginx, Nginx Plus |
Capability có thể chồng lấn: nói theo trách nhiệm, đừng tuyệt đối hóa theo tên sản phẩm. Thêm về Nginx: Nginx.
7. Khi nào nên / không nên
- Nên: nhiều service, nhiều loại client, cần policy chung (auth, rate limit, CORS).
- Không cần: monolith một service; một reverse proxy là đủ.
- Cẩn thận: gateway là SPOF và là hop thêm cho mọi request. Chạy ≥ 2 instance stateless sau LB, ở nhiều AZ; giữ gateway mỏng, không gọi blocking.
Gateway đã validate JWT rồi, vậy các service phía sau có cần kiểm tra token nữa không? Bỏ đi cho nhanh được không?
Bạn hiểu gần đúng, chỉ cần chỉnh một điểm: authentication ở gateway giúp bỏ request rác sớm, nhưng service vẫn nên không tin mù quáng mạng nội bộ (zero trust). Nếu ai đó vào được mạng nội bộ và gọi thẳng Order Service, không có kiểm tra gì là lỗ hổng.
- Cách phổ biến: gateway chuyển tiếp JWT, service validate lại cục bộ bằng public key (JWKS, rẻ, không gọi mạng) và đọc claims để authorization.
- Kèm network policy / mTLS để chỉ gateway và service hợp lệ gọi được nhau.
- Authorization nghiệp vụ (chủ sở hữu order) luôn ở service.
Mọi request đều đi qua gateway, vậy gateway chết là cả hệ thống chết luôn à?
Đúng, nếu chỉ có một instance. Cách xử lý:
Cloud LB (managed, HA sẵn)
/ | \
GW-1 (AZ-a) GW-2 (AZ-b) GW-3 (AZ-c) ← stateless, autoscale
\ | /
Services
- Gateway stateless (state rate limit ở Redis HA), chạy nhiều instance qua nhiều AZ, health check ở LB.
- Gateway mỏng: không business logic, không gọi blocking, timeout rõ ràng với backend.
- Monitor latency và error rate của gateway: nó là chỗ nhìn thấy toàn bộ traffic.
Phỏng vấn hỏi API Gateway khác Load Balancer thế nào thì trả lời sao?
Q1. What's the difference between an API Gateway and a Load Balancer?
🇻🇳 Tiếng Việt:
API Gateway là điểm vào cho API request của client, xử lý routing theo API, authentication, rate limiting, logging và các cross-cutting concern khác. Load balancer chủ yếu phân phối traffic giữa nhiều instance của một service. Cách nghĩ đơn giản: gateway quyết định request đi service nào, load balancer quyết định instance nào. Thực tế capability có thể chồng lấn tùy sản phẩm.
🇬🇧 English:
An API Gateway is the entry point for client API requests. It handles API routing, authentication, rate limiting, logging and other cross-cutting concerns. A load balancer mainly distributes traffic among multiple instances of a service. A simple way to think about it: the gateway decides which service handles a request, and the load balancer decides which instance. In practice their capabilities can overlap depending on the product.
Q2. Authentication và authorization nên đặt ở đâu?
🇻🇳 Tiếng Việt:
Authentication và các luật thô như "route này cần đăng nhập" đặt ở gateway để chặn sớm, trả 401. Authorization nghiệp vụ như "user có phải chủ order không" phải ở service vì chỉ service có data, trả 403. Service vẫn validate token cục bộ, không tin hoàn toàn mạng nội bộ.
🇬🇧 English:
Authentication and coarse rules such as "this route requires login" belong in the gateway so bad requests are rejected early with 401. Business authorization, such as whether the user owns the order, must live in the service because only the service has that data, returning 403. Services still validate the token locally rather than fully trusting the internal network.
Q3. BFF là gì, khi nào dùng?
🇻🇳 Tiếng Việt:
Backend for Frontend là một gateway riêng cho từng loại client, như web, mobile, partner. Nó ghép và cắt dữ liệu đúng nhu cầu client đó, tránh một gateway chung phình to với logic của mọi client. Em dùng khi các client khác nhau rõ rệt về dữ liệu và tốc độ release.
🇬🇧 English:
Backend for Frontend is a dedicated gateway per client type, such as web, mobile or partners. It aggregates and shapes data for that client, so a single shared gateway does not grow with every client's logic. I use it when clients differ significantly in data needs and release cadence.
Cách nhớ ngắn gọn
- Gateway: service nào + có được phép không. LB: instance nào. Discovery: có những instance nào.
- Nginx là công nghệ; gateway và LB là vai trò.
- AuthN ở gateway (401), AuthZ nghiệp vụ ở service (403).
- Gateway mỏng, stateless, ≥ 2 instance, nhiều AZ.
Tự kiểm tra
Gateway và load balancer trả lời hai câu hỏi nào?
Gateway: request cần service nào (và có được phép không). LB: trong các instance của service đó, chọn instance nào.
Vì sao không đặt kiểm tra "chủ sở hữu order" ở gateway?
Gateway không có data nghiệp vụ; chỉ Order Service biết owner của order.
401 và 403 khác nhau thế nào?
401: chưa xác thực/token không hợp lệ. 403: đã xác thực nhưng không có quyền.
Service discovery giúp gateway việc gì?
Biết danh sách instance đang sống của một service (autoscale, chết) để load balancing động thay vì hardcode IP.
Làm sao để gateway không thành SPOF?
Stateless, nhiều instance sau LB có health check, trải trên nhiều AZ, state dùng chung đặt ở Redis HA.