API Gateway, BFF и Service Mesh
Зачем знать: Между клиентом и микросервисами есть слой, который занимается auth, rate limiting, routing, transformation. Это API Gateway или BFF. И между микросервисами есть service mesh — инфраструктурный слой для secure observable communication. Middle Go-разработчик должен понимать разницу между Kong, KrakenD, Envoy и собственным gateway на chi/gin, знать когда BFF (Backend for Frontend) оправдан, и когда service mesh не overkill.
Содержание
Заголовок раздела «Содержание»- Концепция: API Gateway, BFF, Service Mesh
- Реализации: Kong, KrakenD, custom Go, Istio, Linkerd, GraphQL
- Gotchas
- Real cases
- Вопросы (20)
- Practice
- Источники
1. Концепция
Заголовок раздела «1. Концепция»1.1 API Gateway: что это и зачем
Заголовок раздела «1.1 API Gateway: что это и зачем»API Gateway — single entry point для backend services. Все запросы извне идут через него.
┌─── /users ──→ User Service[Client] → [Gateway] ──── /orders ──→ Order Service └─── /payments → Payment ServiceФункции:
- Routing — направить запрос к нужному сервису по path/method/headers.
- Authentication / Authorization — проверка JWT, OAuth2, API keys. Централизованно.
- Rate limiting — ограничение QPS per client/API key.
- Request/response transformation — добавить/удалить headers, переписать body, версионирование.
- Aggregation — соединить ответы от нескольких сервисов в один.
- Caching — кэширование GET ответов.
- Compression — gzip/brotli.
- TLS termination — расшифровка HTTPS, дальше plain HTTP внутри VPC.
- Observability — единая точка для метрик, трейсов, логов.
- Protocol translation — gRPC ↔ REST, WebSocket ↔ HTTP.
Why не client → service directly?
- Клиент не должен знать топологию сервисов.
- Auth и rate limit нужны на каждом сервисе → дубликация.
- CORS, CSP, security headers — лучше централизованно.
1.2 API Gateway вспомогательные термины
Заголовок раздела «1.2 API Gateway вспомогательные термины»- North-south traffic: между клиентом (browser, mobile) и сервисами. Gateway работает здесь.
- East-west traffic: между микросервисами внутри cluster. Service mesh работает здесь.
- Edge gateway: на границе сети, ближе всех к клиенту.
- Internal gateway: между сервисами разных bounded contexts.
1.3 Anti-patterns API Gateway
Заголовок раздела «1.3 Anti-patterns API Gateway»⚠️ Business logic в gateway. Gateway должен быть тонким. Если он считает скидки, валидирует бизнес-правила — это уже сервис, не gateway. Сложно тестировать, дебажить, масштабировать.
⚠️ Шлюз как монолит. Один gateway для 50 микросервисов с сотнями routes — single point of failure и развёртывание становится медленным. Можно дробить на несколько gateways по доменам.
⚠️ Долгие операции в gateway. Timeout gateway = upper bound для всех запросов. Если есть долгие операции (export, video processing) — должны идти через async pattern, не через gateway.
⚠️ State в gateway. Gateway должен быть stateless (rate limit state — внешне, в Redis). Иначе scaling сложен.
1.4 Authentication в gateway
Заголовок раздела «1.4 Authentication в gateway»Pattern: gateway проверяет JWT, передаёт user info в headers вниз.
[Client] Authorization: Bearer eyJ... ↓[Gateway] - Validate JWT signature - Check expiration - Extract user_id, roles ↓[Service] X-User-ID: 42 X-User-Roles: admin,userPros: сервисы не валидируют JWT (быстрее). Доверие headers внутри сети.
⚠️ Защита: убедись, что эти headers нельзя послать клиентом напрямую. Gateway должен зачищать X-User-* из входящих и устанавливать сам.
JWKS rotation: при ротации ключей у IdP gateway периодически обновляет JWKS. Не хардкодить ключ.
1.5 Rate limiting в gateway
Заголовок раздела «1.5 Rate limiting в gateway»Алгоритмы:
- Fixed window: сбрасывается каждую минуту. Spike на границе окна (2 минуты — двойной burst).
- Sliding window: скользящее окно (log запросов). Точнее, но дороже по памяти.
- Token bucket: burst-friendly. Используется в
golang.org/x/time/rate. - Leaky bucket: стабильный rate, без burst.
Storage:
- Redis для distributed (несколько gateway instances).
- In-memory только для single instance.
Keys:
- Per IP (для DDoS protection).
- Per API key (для quotas customer’ов).
- Per endpoint (защита тяжёлого endpoint).
- Per user (для logged-in).
1.6 BFF (Backend for Frontend)
Заголовок раздела «1.6 BFF (Backend for Frontend)»Pattern (Sam Newman, ThoughtWorks 2015): каждый frontend (mobile, web, partner API) имеет свой backend. Не один API на всех.
[iOS app] → [BFF iOS][Web app] → [BFF Web] ──→ [Microservices...][Partners] → [BFF Partner]Зачем:
- Mobile хочет минимум данных (battery, network) → BFF aggregates, returns compact JSON.
- Web хочет богатые данные с relationships → BFF делает joins.
- Partners хотят stable contract → BFF изолирует от внутренних изменений.
Преимущества:
- Each BFF владеет своей frontend-командой.
- Backwards compatibility per client.
- Aggregation reduces round-trips (N+1 problem mobile).
Trade-offs:
- Больше сервисов = больше maintenance.
- Дублирование логики (несколько BFF делают похожие вещи).
Когда BFF не нужен: небольшая команда, один frontend → один API достаточно.
1.7 Aggregator pattern
Заголовок раздела «1.7 Aggregator pattern»BFF может агрегировать данные из нескольких сервисов:
func (b *BFF) GetOrderDetails(ctx context.Context, orderID string) (OrderDetails, error) { var order Order var customer Customer var items []Item g, ctx := errgroup.WithContext(ctx)
g.Go(func() error { var err error order, err = b.orderService.Get(ctx, orderID) return err }) g.Go(func() error { var err error items, err = b.itemService.List(ctx, orderID) return err })
if err := g.Wait(); err != nil { return OrderDetails{}, err }
// customer зависит от order customer, err := b.customerService.Get(ctx, order.CustomerID) if err != nil { return OrderDetails{}, err }
return OrderDetails{Order: order, Customer: customer, Items: items}, nil}Параллельные вызовы через errgroup снижают latency.
1.8 GraphQL как BFF
Заголовок раздела «1.8 GraphQL как BFF»GraphQL хорошо подходит для BFF: клиент сам выбирает поля и связи.
query { order(id: "123") { id total customer { name email } items { title price } }}Один запрос → BFF делает 3 вызова к microservices → возвращает структуру.
1.9 Service Mesh
Заголовок раздела «1.9 Service Mesh»Service Mesh = инфраструктурный слой для service-to-service связи. Решает проблемы:
- Service discovery.
- Load balancing.
- Encryption (mTLS).
- Retries, timeouts, circuit breaking.
- Observability (metrics, tracing, logging).
- Traffic management (canary, A/B, blue-green).
Архитектура: sidecar pattern — у каждого pod’а есть второй контейнер (proxy, обычно Envoy). Весь сетевой трафик идёт через proxy.
[Pod] ├── [App container] │ ↕ localhost ├── [Envoy sidecar] │ ↕ network[Pod] ├── [Envoy sidecar] │ ↕ localhost ├── [App container]Control plane (Istio, Linkerd) программирует sidecars через xDS API.
Преимущества:
- Язык-агностично (не нужны клиенты в каждом языке).
- Observability “из коробки”.
- mTLS прозрачно.
- Traffic management без изменения кода.
Недостатки:
- Resource overhead (~50MB RAM на sidecar, +5-10% CPU).
- Сложность дебага (теперь и Envoy надо смотреть).
- Latency +1-3ms per hop.
1.10 Ambient Mesh (Istio 2024+)
Заголовок раздела «1.10 Ambient Mesh (Istio 2024+)»Новый подход без sidecars: per-node ztunnel (для L4: mTLS, ID) + per-namespace waypoint proxy (для L7: HTTP routing).
Pros: меньше overhead (один ztunnel на node вместо sidecar на pod). Cons: новее, меньше production deployments.
1.11 Когда service mesh оправдан
Заголовок раздела «1.11 Когда service mesh оправдан»Нужен:
- Десятки+ микросервисов.
- mTLS обязателен (compliance).
- Multi-team разработка с разными tech stacks.
- Сложные traffic management требования (canary, mirroring).
Не нужен:
- Маленький проект (<5 сервисов) — sidecar overhead не окупится.
- Простой north-south case — API Gateway достаточно.
- Высокие требования к latency (<1ms p99) — каждый hop добавляет.
2. Реализации
Заголовок раздела «2. Реализации»2.1 Kong
Заголовок раздела «2.1 Kong»Самый популярный API Gateway. Open source, на NGINX + Lua. Enterprise version от Kong Inc.
Архитектура:
- DB-backed (PostgreSQL/Cassandra) или DB-less (declarative YAML).
- Plugins: auth (JWT, OAuth2, key-auth), rate-limiting, transformations, logging, monitoring.
Конфиг:
services: - name: payment-service url: http://payment-svc:8080 routes: - paths: ["/payments"] plugins: - name: rate-limiting config: minute: 100 - name: jwtKong поддерживает Go plugins через go-pdk. Можно писать custom logic на Go.
2.2 KrakenD
Заголовок раздела «2.2 KrakenD»Go-native API Gateway. Stateless, конфиг через JSON, очень быстрый.
Конфиг (krakend.json):
{ "endpoints": [ { "endpoint": "/api/order/{id}", "method": "GET", "backend": [ { "url_pattern": "/orders/{id}", "host": ["http://order-svc"] }, { "url_pattern": "/customers/{customer_id}", "host": ["http://customer-svc"] } ] } ]}Aggregation из коробки. Конфигом задаются backends, KrakenD сам делает параллельные запросы и мерджит JSON.
2.3 Tyk
Заголовок раздела «2.3 Tyk»Go-native, открытый код. Сильнее в API management (versioning, analytics, developer portal).
2.4 Envoy + custom routing
Заголовок раздела «2.4 Envoy + custom routing»Envoy сам по себе — proxy, не API Gateway. Но с конфигом можно использовать как gateway.
listeners: - address: { socket_address: { address: 0.0.0.0, port_value: 80 } } filter_chains: - filters: - name: envoy.filters.network.http_connection_manager typed_config: "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager route_config: virtual_hosts: - name: payment domains: ["*"] routes: - match: { prefix: "/payments" } route: { cluster: payment-service } http_filters: - name: envoy.filters.http.jwt_authn - name: envoy.filters.http.ratelimit - name: envoy.filters.http.routerEnvoy Gateway (CNCF проект 2023) — управление Envoy через Kubernetes Gateway API.
2.5 Custom Go API Gateway
Заголовок раздела «2.5 Custom Go API Gateway»Для простых случаев — собственный gateway на chi/gin/echo.
Пример на chi:
package main
import ( "net/http" "net/http/httputil" "net/url"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware")
func main() { r := chi.NewRouter()
// Common middleware r.Use(middleware.RequestID) r.Use(middleware.RealIP) r.Use(middleware.Logger) r.Use(middleware.Recoverer) r.Use(authMiddleware) r.Use(rateLimitMiddleware)
// Routing r.Handle("/payments/*", proxyTo("http://payment-svc:8080")) r.Handle("/orders/*", proxyTo("http://order-svc:8080")) r.Handle("/users/*", proxyTo("http://user-svc:8080"))
http.ListenAndServe(":80", r)}
func proxyTo(target string) http.Handler { u, _ := url.Parse(target) proxy := httputil.NewSingleHostReverseProxy(u) proxy.ModifyResponse = func(r *http.Response) error { r.Header.Set("X-Gateway", "go-gw") return nil } return proxy}
func authMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("Authorization") claims, err := validateJWT(token) if err != nil { http.Error(w, "unauthorized", 401) return } r.Header.Set("X-User-ID", claims.Subject) next.ServeHTTP(w, r) })}
func rateLimitMiddleware(next http.Handler) http.Handler { limiter := rate.NewLimiter(1000, 100) // 1000 req/s, burst 100 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if !limiter.Allow() { http.Error(w, "rate limit", 429) return } next.ServeHTTP(w, r) })}Когда custom gateway оправдан:
- Простые routes (<20).
- Специфичные требования, не покрываемые Kong/KrakenD.
- Команда сильна в Go.
Когда нет:
- Сложные plugins (auth provider integration, observability).
- Много routes — поддерживать дороже.
- Не хватает экспертизы.
2.6 Istio
Заголовок раздела «2.6 Istio»Самый feature-rich service mesh. Envoy data plane + Istiod control plane.
Установка:
istioctl install --set profile=defaultkubectl label namespace prod istio-injection=enabledПосле label — Istio injects Envoy sidecar в каждый новый pod автоматически.
Traffic management через VirtualService:
apiVersion: networking.istio.io/v1kind: VirtualServicemetadata: name: paymentspec: hosts: - payment http: - match: - headers: user-agent: regex: ".*Mobile.*" route: - destination: host: payment subset: v2 - route: - destination: host: payment subset: v1 weight: 90 - destination: host: payment subset: v2 weight: 1010% трафика на v2 (canary), плюс mobile получает v2 целиком.
DestinationRule для CB:
apiVersion: networking.istio.io/v1kind: DestinationRulemetadata: name: payment-cbspec: host: payment trafficPolicy: connectionPool: tcp: maxConnections: 100 http: http1MaxPendingRequests: 50 outlierDetection: consecutive5xxErrors: 5 interval: 30s baseEjectionTime: 30s2.7 Linkerd
Заголовок раздела «2.7 Linkerd»Lightweight service mesh. Rust data plane (linkerd2-proxy), Go control plane.
Преимущества:
- Проще, меньше overhead (~10MB RAM per sidecar vs Istio’s 50MB).
- Опеннисить и поддерживать.
- Лучше latency.
Недостатки:
- Меньше функций (например, ограниченный traffic shaping).
- Меньше экосистема.
Установка:
linkerd install | kubectl apply -f -kubectl annotate ns prod linkerd.io/inject=enabled2.8 Consul Connect
Заголовок раздела «2.8 Consul Connect»Service mesh от HashiCorp. Intergates с Consul service registry.
Features: mTLS, intentions (firewall rules), observability. Слабее Istio в traffic management.
2.9 GraphQL в Go
Заголовок раздела «2.9 GraphQL в Go»gqlgen — самая популярная Go библиотека. Schema-first, codegen.
Workflow:
- Описываешь schema в
.graphqlфайле. - Запускаешь
go run github.com/99designs/gqlgen generate. - Реализуешь resolvers.
Schema:
type Query { order(id: ID!): Order}
type Order { id: ID! total: Float! customer: Customer! items: [Item!]!}
type Customer { id: ID! name: String! email: String!}
type Item { id: ID! title: String! price: Float!}Resolver:
func (r *queryResolver) Order(ctx context.Context, id string) (*model.Order, error) { return r.orderService.Get(ctx, id)}
func (r *orderResolver) Customer(ctx context.Context, obj *model.Order) (*model.Customer, error) { return r.customerService.Get(ctx, obj.CustomerID)}
func (r *orderResolver) Items(ctx context.Context, obj *model.Order) ([]*model.Item, error) { return r.itemService.ListByOrder(ctx, obj.ID)}2.10 N+1 problem в GraphQL: DataLoader
Заголовок раздела «2.10 N+1 problem в GraphQL: DataLoader»Если у заказа 100 items и каждый item имеет customer (отдельный resolver), то 100 запросов в customer service — это N+1 проблема.
DataLoader pattern: батчинг + кэширование.
import "github.com/graph-gophers/dataloader/v7"
type CustomerLoader struct { loader *dataloader.Loader[string, *Customer]}
func NewCustomerLoader(svc *CustomerService) *CustomerLoader { batch := func(ctx context.Context, ids []string) []*dataloader.Result[*Customer] { customers, err := svc.BatchGet(ctx, ids) results := make([]*dataloader.Result[*Customer], len(ids)) if err != nil { for i := range ids { results[i] = &dataloader.Result[*Customer]{Error: err} } return results } m := make(map[string]*Customer) for _, c := range customers { m[c.ID] = c } for i, id := range ids { results[i] = &dataloader.Result[*Customer]{Data: m[id]} } return results } return &CustomerLoader{loader: dataloader.NewBatchedLoader(batch)}}
// В resolverfunc (r *orderResolver) Customer(ctx context.Context, obj *Order) (*Customer, error) { return r.customerLoader.Load(ctx, obj.CustomerID)()}DataLoader собирает все Load() calls в течение тика, выполняет один Batch запрос.
2.11 Persisted queries
Заголовок раздела «2.11 Persisted queries»В GraphQL клиент посылает query (текст), сервер парсит. Угрозы:
- Огромные queries (DOS).
- Малоизвестные queries (DOS).
Persisted queries: клиент посылает только hash, сервер ищет в whitelist.
// Client отправляет:POST /graphql{ "id": "5f3a4b2c", "variables": {"id": "123"} }
// Server resolves id → query → executes.Используется Apollo Client, Relay. Защищает от arbitrary queries.
2.12 Subscriptions over WebSocket
Заголовок раздела «2.12 Subscriptions over WebSocket»GraphQL subscriptions для real-time. WebSocket transport.
type Subscription { orderUpdates(orderID: ID!): Order}gqlgen поддерживает через Server.AddTransport(transport.Websocket{}).
⚠️ WebSocket сложнее scale, чем HTTP. Sticky session, или Redis pub/sub broadcast между instances.
3. Gotchas
Заголовок раздела «3. Gotchas»⚠️ Gateway — single point of failure. Деплой gateway в HA (>1 instance), TLS terminate behind LB.
⚠️ Долгие requests заполняют gateway. Если backend медленный, gateway connections заняты → новые клиенты не пройдут. Тaймауты + concurrency limits.
⚠️ JWT validation overhead. Каждый запрос — RSA verify (CPU-intensive). Cache verified tokens на TTL.
⚠️ CORS в gateway vs service. Стандартизуй: либо gateway добавляет, либо service. Иначе либо дубли, либо пропуски.
⚠️ Headers форвардинг. X-Forwarded-For, X-Real-IP, X-Request-ID должны прокидываться. Service видит реальный client IP, не gateway IP.
⚠️ X-Forwarded-Proto. Если gateway терминирует TLS, downstream видит HTTP. Если внутри генерируется ссылка — она будет http://, не https://. Используй X-Forwarded-Proto header.
⚠️ Sticky session vs scaling. Если sticky session в gateway (одну session на один backend pod), scaling и rolling deploy ломают. Хранить session в Redis.
⚠️ API versioning. /v1/orders vs /orders + X-API-Version header. Header version часто проще для gateway routing.
⚠️ Aggregation: failure handling. Если из 3 backends один упал, что вернуть? Partial response, 503, default values? Зависит от UX.
⚠️ Sidecar overhead в маленькой системе. 100MB RAM (Istio) на каждый pod × 50 pods = 5GB только на mesh. Бюджет!
⚠️ mTLS rotation. Sidecar обновляет cert автоматически (24h TTL обычно). Если падает control plane — certs истекают → outage.
⚠️ Envoy retry vs client retry. Двойной retry мультиплицирует нагрузку. Disable один из них.
⚠️ GraphQL N+1. Без DataLoader каждый поле — отдельный запрос. Профилируй! Используй tracing.
⚠️ GraphQL DOS. Глубокие nested queries: user { posts { comments { author { posts { ... } } } } }. Limit query depth и complexity.
⚠️ GraphQL authorization. Поля не имеют URL → авторизация на каждом поле. Используй middleware на resolver level.
⚠️ BFF дублирование. Без чёткого ownership одна логика реплицируется в нескольких BFF. Code review, shared libs.
⚠️ Gateway не replaces auth in services. Если злоумышленник попадёт мимо gateway (внутри сети), сервис не должен слепо доверять. Defense in depth: mTLS, JWT validation в сервисе тоже.
4. Real cases
Заголовок раздела «4. Real cases»Netflix Zuul / Zuul 2. Zuul 1 — gateway на Java, синхронный (blocking). Zuul 2 — async, Netty-based. Netflix постепенно мигрировал на Envoy + custom control plane.
Kong на Cloudflare Workers. Cloudflare Workers — edge compute platform. Можно использовать как distributed API gateway, JS/Rust/Wasm.
Tinder API Gateway.
Кастомный на Go. Routing, auth, rate limit, A/B test traffic splitting. Open sourced как tron (часть).
Spotify GraphQL BFF (Apollo Federation). Spotify использует federated GraphQL: gateway соединяет схемы от разных subgraphs (microservices). Apollo Federation.
GitHub GraphQL API. GitHub предоставляет GraphQL API параллельно с REST. Persisted queries для security и performance. https://docs.github.com/en/graphql
Shopify API Gateway. Кастомный gateway, оптимизированный для GraphQL. Shopify ranks one of largest GraphQL deployments. Federated.
Uber — Edge Gateway. Изначально custom, мигрировали на gRPC + Envoy. Service mesh внутри.
Lyft Envoy. Envoy создан в Lyft (2016), Open sourced, теперь CNCF. Используется как edge proxy и sidecar.
Yandex.Cloud API Gateway. Cloud-managed API Gateway. Поддержка OpenAPI specs, auth via Cloud Identity, integration с Functions.
Tinkoff API Gateway. Внутренний gateway на Go. Routing, JWT, rate limit, observability (OpenTelemetry).
Istio adoption. Используется eBay, Salesforce, IBM Cloud, Cisco Webex, Mux. Сложности — Lyft изначально создал Envoy специально, потому что других решений не было. Istio добавил complexity layer поверх.
Linkerd adoption. Microsoft, Walmart, Salesforce, HSBC. Многие выбирают Linkerd за простоту.
KrakenD у Saude (Brazil healthtech). KrakenD ~13K req/s на 1 pod 1 CPU. Aggregation 3-4 backends в один endpoint.
Cloudflare API Shield. Edge service: API discovery, schema validation, ML-based abuse detection. Managed API gateway.
5. Вопросы
Заголовок раздела «5. Вопросы»Q1: Что такое API Gateway? A: Single entry point для backend services. Делает routing, auth, rate limiting, transformation, aggregation. Защищает от прямого доступа клиентов к internals.
Q2: Какие функции должен иметь API Gateway? A: Routing, authentication, rate limiting, request/response transformation, TLS termination, observability, optionally aggregation и caching.
Q3: Что не должно быть в gateway? A: Business logic, persistent state. Gateway — тонкий слой. Бизнес-правила — в сервисах.
Q4: North-south vs east-west traffic — в чём разница? A: North-south — между клиентами и системой (gateway). East-west — между микросервисами внутри (service mesh).
Q5: Какие популярные API Gateway существуют? A: Kong (NGINX-based), KrakenD (Go-native), Tyk (Go), Envoy (proxy), Cloud-managed (AWS API Gateway, Cloudflare).
Q6: Когда писать custom gateway на Go? A: Простые routes (<20), специфичные требования, команда сильна в Go. Не для сложных кейсов (auth providers, observability).
Q7: Что такое BFF (Backend for Frontend)? A: Отдельный backend для каждого frontend (mobile, web, partner). Каждый BFF оптимизирован под нужды клиента. Pattern Sam Newman 2015.
Q8: Зачем BFF, а не один универсальный API? A: Mobile хочет компактные данные (battery), web — богатые с relationships, partners — стабильный contract. BFF изолирует каждый клиент.
Q9: Что такое aggregator pattern? A: Gateway/BFF собирает данные из нескольких сервисов в один ответ. Снижает N+1 для клиентов (один запрос вместо нескольких).
Q10: Как сделать параллельные запросы в Go?
A: errgroup.WithContext запускает goroutines, ждёт всех. При ошибке одного — отменяет остальные через context.
Q11: Что такое service mesh? A: Инфраструктурный слой для service-to-service. Sidecar proxy (Envoy) на каждом pod’е. Решает discovery, mTLS, retries, observability на инфра-уровне.
Q12: Когда service mesh не нужен? A: Маленькая система (<5 сервисов), простой north-south case, требования к ultra-low latency (<1ms p99). Overhead не окупается.
Q13: В чём разница Istio и Linkerd? A: Istio — feature-rich, Envoy proxy, ~50MB RAM/sidecar. Linkerd — lightweight, Rust proxy, ~10MB. Istio для enterprise, Linkerd для большинства.
Q14: Что такое Ambient Mesh? A: Istio 2024+ подход без sidecars. Per-node ztunnel + per-namespace waypoint proxy. Меньше overhead, новее.
Q15: Что такое GraphQL и зачем? A: Query language для API. Клиент выбирает поля и связи в одном запросе. Подходит для BFF: разные клиенты с разными нуждами.
Q16: Какая популярная Go библиотека для GraphQL?
A: gqlgen (99designs) — schema-first, code generation. graphql-go — code-first.
Q17: Что такое N+1 проблема в GraphQL? A: Каждый nested field вызывает отдельный resolver. Список из N items с relations → N+1 запросов в downstream. Решение: DataLoader (батчинг + кэш).
Q18: Persisted queries — что это? A: Клиент посылает hash вместо текста query. Сервер ищет в whitelist. Защита от arbitrary queries, DOS. Apollo Client, Relay.
Q19: Как защитить GraphQL от DOS? A: Query depth limit, complexity scoring (cost per field), persisted queries, rate limit на queries (не на HTTP calls).
Q20: GraphQL vs REST для BFF — что выбрать? A: GraphQL — гибкость для разных клиентов, меньше эндпоинтов. REST — проще caching, простой routing. GraphQL для variety frontends, REST для simple/stable contracts.
6. Practice
Заголовок раздела «6. Practice»-
Реализуй простой API Gateway на chi с middleware: auth (JWT), rate limit (Redis), logging, proxy на 3 backend services.
-
Aggregator endpoint. Endpoint
/order/detailsделает параллельно 3 вызова к order/customer/items services через errgroup. Сравни latency vs sequential. -
JWT validation middleware с JWKS rotation. Кэшируй keys, refresh при unknown kid.
-
Rate limiting с token bucket в Redis. Key = client IP. 100 req/min, burst 20.
-
Установи Istio в minikube, задеплой 2 сервиса. Включи mTLS (PeerAuthentication STRICT). Покажи захват трафика на mTLS handshake.
-
Canary deployment с Istio. VirtualService: 90% на v1, 10% на v2. Метрики через kiali.
-
GraphQL сервер с gqlgen. Schema Order/Customer/Items. Resolvers с DataLoader для customer.
-
Сравни overhead Linkerd vs Istio. Деплой 10 pods с/без mesh. Замерь RAM, CPU, latency.
-
BFF для mobile и web. Mobile BFF возвращает compact JSON (только id, title), web — полный объект. Один backend на двух конце.
-
Persisted queries. Whitelist queries по hash в server-side store. Client отправляет hash.
7. Источники
Заголовок раздела «7. Источники»- Sam Newman. “Pattern: Backends For Frontends.” 2015. https://samnewman.io/patterns/architectural/bff/
- Chris Richardson. “Microservices Patterns.” Manning, 2018. — главы про API Gateway.
- Kong Documentation. https://docs.konghq.com
- KrakenD docs. https://www.krakend.io/docs/
- Istio Documentation. https://istio.io/latest/docs/
- Linkerd Documentation. https://linkerd.io/2/overview/
- Envoy Proxy Documentation. https://www.envoyproxy.io/docs/envoy/latest/
- gqlgen documentation. https://gqlgen.com/
- Apollo Federation. https://www.apollographql.com/docs/federation/
- Lin Sun, Daniel Berg. “Istio in Action.” Manning, 2022.
- William Morgan. “The Service Mesh: What every software engineer needs to know about the world’s most over-hyped technology.”
- CNCF Service Mesh landscape. https://landscape.cncf.io/