🏗️ Розділ 17 · Питання #9

Що таке API Gateway і які завдання він вирішує

Без API Gateway клієнту довелося б: 4. Залежати від внутрішніх змін мережевої топології компанії.


🟢 Junior Level

API Gateway (Шлюз API) — це єдина точка входу (Single Point of Entry) та спеціалізований прикордонний сервіс (Edge Service), через який зовнішні клієнти (веб-браузери, мобільні застосунки, сторонні інтеграції) взаємодіють із внутрішньою мікросервісною екосистемою.

Зовнішній світ:                      Периметр:               Внутрішній контур (Private Network):
[Mobile App]  ───┐                                                 ┌──► [User Service]
                 ├──HTTPS (Public IP)──► ┌───────────────────┐    │
[Web SPA]     ───┼─────────────────────► │    API Gateway    │────┼──► [Order Service]
                 │                       │ (Netty / Envoy)   │    │
[Third-Party] ───┘                       └───────────────────┘    └──► [Payment Service]

Навіщо він потрібен?

Без API Gateway клієнту довелося б:

  1. Знати мережеві адреси десятків мікросервісів і надсилати десятки окремих HTTP-запитів для відмальовки одного екрана.
  2. Проходити автентифікацію в кожному сервісі окремо.
  3. Страждати від проблем із CORS (Cross-Origin Resource Sharing).
  4. Залежати від внутрішніх змін мережевої топології компанії.

Головні завдання:

  • Маршрутизація (Routing): Перенаправлення запиту /api/v1/orders в order-service.
  • Автентифікація та безпека: Перевірка JWT-токенів на вході, завершення SSL/TLS (TLS Termination), захист від DDoS.
  • Обмеження трафіку (Rate Limiting): Захист сервісів від перевантаження (наприклад, не більше 100 запитів на хвилину на користувача).
  • Наскрізна функціональність (Cross-Cutting Concerns): Генерація Correlation-ID, збір метрик, логування, CORS.

🟡 Middle Level

1. Архітектура Spring Cloud Gateway

Сучасний Spring Cloud Gateway побудований на неблокуючому реактивному стеку (Project Reactor + Netty + Spring WebFlux).

Він складається з трьох ключових сутностей:

  1. Route (Маршрут): Базовий блок, що включає ID, цільовий URI, набір предикатів та фільтрів.
  2. Predicate (Предикат): Java Predicate<ServerWebExchange>, що перевіряє відповідність запиту умовам (URL-шлях, HTTP-метод, наявність заголовків, cookies).
  3. Filter (Фільтр): Модифікатор вхідного запиту (Pre-filter) або вихідної відповіді (Post-filter).
@Configuration
public class GatewayRoutesConfig {

    @Bean
    public RouteLocator customRoutes(RouteLocatorBuilder builder,
                                     JwtAuthenticationFilter authFilter,
                                     RedisRateLimiter redisRateLimiter) {
        return builder.routes()
            .route("order-service-route", r -> r
                .path("/api/v1/orders/**")
                .and().method(HttpMethod.GET, HttpMethod.POST)
                .filters(f -> f
                    .filter(authFilter) // Перевірка токена та вилучення заголовків
                    .requestRateLimiter(c -> c
                        .setRateLimiter(redisRateLimiter)
                        .setKeyResolver(exchange -> ReactiveSecurityContextHolder.getContext()
                            .map(ctx -> ctx.getAuthentication().getName())))
                    .circuitBreaker(c -> c
                        .setName("orderServiceCircuitBreaker")
                        .setFallbackUri("forward:/fallback/orders"))
                    .stripPrefix(1) // Перетворює /api/v1/orders/123 на /v1/orders/123
                )
                .uri("lb://order-service") // Резолв через Service Discovery
            )
            .build();
    }
}

2. Завдання, які вирішує API Gateway

[Вхідний HTTP-запит]
       │
       ▼
[1. TLS Termination]     ──► Зняття HTTPS, дешифрування на межі мережі
       │
       ▼
[2. WAF & Anti-DDoS]     ──► Блокування SQLi, XSS, бот-трафіку
       │
       ▼
[3. Rate Limiter]        ──► Redis Token Bucket (429 Too Many Requests при перевищенні)
       │
       ▼
[4. Authentication]      ──► Валідація JWT, розшифровка claims
       │
       ▼
[5. Tracing / Headers]   ──► Генерація X-Request-ID, додавання X-User-Id: 42
       │
       ▼
[6. Protocol Conversion] ──► Перетворення HTTP/JSON у внутрішній gRPC / Protobuf
       │
       ▼
[7. Reverse Proxy]       ──► Відправлення в цільовий под у внутрішню мережу

🔴 Senior Level

1. Архітектурні шаблони безпеки: Token Relay vs Phantom Token

Як безпечно передати дані про автентифікацію від Gateway до внутрішніх мікросервісів?

  1. Token Relay Pattern: Gateway перевіряє підпис зовнішнього JWT і прокидає його в незмінному вигляді в заголовок Authorization: Bearer <token> у внутрішню мережу.
    • Мінус: Якщо JWT містить надлишкові дані (PII, скоупи), внутрішні сервіси витрачають CPU на повторну валідацію криптографії.
  2. Phantom Token Pattern (Рекомендований):
    • Клієнт з мобільного пристрою шле Reference Token (непрозорий UUID, випадковий рядок).
    • Gateway звертається до Authorization Server (Keycloak/Hydra) або кешу Redis, валідує reference token і замінює його на криптографічно підписаний внутрішній JWT-токен із потрібними claims.
    • Внутрішні мікросервіси довіряють Gateway і швидко читають заголовки X-User-Id та X-User-Roles.
[SPA / Mobile] ──(Opaque Token: "xyz789")──► [API Gateway]
                                                   │ 1. Валідація в Keycloak/Redis
                                                   ▼ 2. Випуск JWT
                                             [Внутрішній мікросервіс]
                                             (Отримує JWT / заголовки X-User-Id)

2. Антипатерн «Smart Gateway» (God Gateway)

Найбільш руйнівна помилка при експлуатації API Gateway — перетворення його на монолітний вузол бізнес-логіки:

  • Помилки: Розміщення в шлюзі бізнес-валідацій, звернень до БД, трансформації складних JSON-схем, викликів ланцюжків сервісів (API Orchestration / Heavy Aggregation).
  • Наслідки: Команди мікросервісів блокують одна одну в черзі на деплой шлюзу; шлюз падає від витоків пам’яті; CPU вичерпується на серіалізації даних.
  • Правило: Gateway повинен бути «тонким роутером» (Smart endpoints, dumb pipes). Допускається лише маршрутизація, фільтрація та наскрізні технічні аспекти. Для агрегації даних екранів використовують BFF (Backend for Frontend) або GraphQL Federation.

3. API Gateway vs Kubernetes Ingress Controller vs Service Mesh Ingress

Компонент Головна зона відповідальності Приклади
Kubernetes Ingress Базовий L7-роутинг трафіку ззовні кластера K8s до внутрішніх сервісів (path/host routing, TLS). Nginx Ingress Controller, Traefik
API Gateway Розширена бізнес-орієнтована безпека (OAuth2/OIDC, Rate Limiting за ключами API, монетизація API, трансформація запитів). Kong, Spring Cloud Gateway, Apigee, KrakenD
Service Mesh Ingress (Envoy) Керування мережевим трафіком, mTLS, канарковий деплой (Canary 90/10), збір мережевої телеметрії без прив’язки до застосунку. Istio Ingress Gateway, Linkerd

У сучасних хмарних архітектурах вони часто об’єднуються: Kubernetes Gateway API на базі Envoy виконує ролі і Ingress, і API Gateway.


4 Tricky Questions

1. Чому Spring Cloud Gateway побудований на реактивному стеку (Netty + WebFlux), а не на класичному сервлетному Tomcat (як Zuul 1)?

Відповідь: Класичний сервлетний стек (Tomcat / Zuul 1) працює за моделлю Thread-per-Request: кожен вхідний HTTP-запит займає окремий потік ОС. Шлюз є I/O-інтенсивним застосунком (він не виконує важких обчислень, а чекає відповідей від бекендів). При тисячах одночасних повільних запитів пул із 200–500 потоків Tomcat миттєво вичерпується, призводячи до паралічу шлюзу. Spring Cloud Gateway використовує неблокуючий Event Loop (Netty), де жменька потоків (рівна числу ядер CPU) здатна мультиплексувати десятки тисяч одночасних мережевих з’єднань без перемикання контексту потоків ОС.

2. Що таке API Composition (Aggregation) на шлюзі і чому на високих навантаженнях це перетворюється на проблему?

Відповідь: API Composition — це коли шлюз за одним запитом клієнта паралельно викликає 5 мікросервісів (користувач, замовлення, кошик, рекомендації, сповіщення), збирає їхні відповіді в єдиний JSON і віддає клієнту. Проблема на високих навантаженнях:

  1. Fan-Out Latency: Час відповіді шлюзу стає рівним часу найповільнішого з 5 сервісів (Tail Latency).
  2. Пам’ять та збирання сміття (GC): Шлюз змушений десеріалізувати й утримувати в оперативній пам’яті гігантські графи об’єктів перед склеюванням, що провокує Stop-the-World паузи GC. Рішення: Перенесення агрегації в спеціалізований BFF-шар або використання асинхронного GraphQL Federation.

3. Як реалізувати розподілений Rate Limiting на API Gateway за наявності 10 паралельних інстансів шлюзу?

Відповідь: Локальні in-memory лічильники не підходять, оскільки балансувальник розподіляє запити між 10 інстансами шлюзу, і клієнт зможе перевищити квоту в 10 разів. Рішення: Використання Redis Token Bucket:

  1. Усі інстанси шлюзу звертаються до спільного кластера Redis.
  2. Перевірка та списання токенів виконується атомарно через Lua-скрипт (вбудований у Spring Cloud Gateway RedisRateLimiter), що виключає race conditions.
  3. При вичерпанні ліміту повертається статус HTTP 429 Too Many Requests із заголовком Retry-After.

4. У чому небезпека перевірки цифрового підпису JWT-токена (RSA / ECDSA) на кожен запит у шлюзі при 100 000 RPS?

Відповідь: Перевірка асиметричного криптографічного підпису (RS256) є ресурсомісткою математичною операцією для CPU. При 100 000 RPS шлюз може вичерпати всі доступні ядра процесора виключно на перевірці підписів токенів. Оптимізація:

  • Кешування валідованих токенів у локальному in-memory кеші (Caffeine) на час їхнього життя (TTL) за хешем токена.
  • Використання еліптичних кривих (ES256 / EdDSA), які вимагають значно менше процесорного часу порівняно з важкими ключами RSA 2048/4096.

🎯 Шпаргалка для інтерв’ю

Головне:

  • API Gateway — централізовані вхідні двері в мікросервісну систему.
  • Базові функції: Роутинг, TLS Termination, автентифікація (JWT/OAuth2), Rate Limiting, CORS, трасування (Correlation-ID).
  • Стек: У Java-світі стандартом є реактивний Spring Cloud Gateway (WebFlux + Netty). Поза Java — Kong, Envoy, Nginx, Traefik.
  • Архітектурний принцип: «Тонкий і простий шлюз» (Smart endpoints, dumb pipes). Жодної важкої бізнес-логіки та роботи з БД у шлюзі!
  • Для агрегації різнорідних клієнтських інтерфейсів використовується шаблон BFF (Backend for Frontend), а не перевантаження центрального Gateway.

Запобіжники на шлюзі:

  1. Обов’язковий Rate Limiter (Redis Token Bucket).
  2. Обов’язковий Circuit Breaker (Resilience4j / Reactive CircuitBreaker) на кожен маршрут.
  3. Жорсткі HTTP Connection/Read Timeouts на бекенди.

Червоні прапорці (Чого говорити НЕ МОЖНА):

  • ❌ «В API Gateway ми пишемо валідацію бізнес-правил і пишемо аудит напряму в базу даних» (Шлюз деградує в моноліт і стає SPOF).
  • ❌ «Spring Cloud Gateway працює на базі Tomcat сервлетів» (Він реактивний і працює виключно на Netty/WebFlux).
  • ❌ «Для масштабування шлюзу достатньо одного інстанса» (Шлюз зобов’язаний працювати в HA-кластері з кількох реплік за апаратним або хмарним балансувальником).

Пов’язані теми: