API Gateway, Load Balancer, Nginx: ai làm việc gì?

4 câu hỏi~25 phútTừ khóa: API Gateway, load balancer, reverse proxy, Nginx, authentication, authorization, BFF, service discovery, SPOF

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 đề

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:

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 GatewayLoad BalancerNginx
Bản chấtVai trò/patternVai trò/conceptMột công nghệ cụ thể
Câu hỏi chínhRequest 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ìnhAuth, rate limit, routing theo API, transform, versioningPhân phối traffic, health checkReverse proxy, LB, TLS, cache, static file, rate limit
Ví dụSpring Cloud Gateway, Kong, AWS API GatewayAWS ALB/NLB, Azure LBNginx, 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

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.

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

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


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.