skills/software-architecture-design/references/api-gateway-service-mesh.md

598 lines
22 KiB
Markdown

# API Gateway & Service Mesh Patterns
Deep reference for API gateway architectures, service mesh implementation (Istio, Linkerd, Envoy), sidecar patterns, and service-to-service communication. Use when designing inter-service communication, implementing traffic management, or choosing between gateway, mesh, or hybrid topologies.
## Contents
- [API Gateway Patterns](#api-gateway-patterns)
- [Service Mesh Architecture](#service-mesh-architecture)
- [Technology Comparison](#technology-comparison)
- [mTLS and Service Identity](#mtls-and-service-identity)
- [Observability Through Mesh](#observability-through-mesh)
- [Gateway vs Mesh vs Both](#gateway-vs-mesh-vs-both)
- [Implementation Patterns](#implementation-patterns)
- [Anti-Patterns](#anti-patterns)
- [Decision Framework](#decision-framework)
- [Cross-References](#cross-references)
---
## API Gateway Patterns
### Core Gateway Responsibilities
| Function | Description | Example |
|----------|-------------|---------|
| Routing | Route requests to backend services | `/api/orders/*` -> orders-service |
| Authentication | Validate tokens, API keys | JWT verification, OAuth introspection |
| Rate limiting | Throttle requests per client/endpoint | 100 req/min per API key |
| Request transformation | Modify headers, body, path | Add correlation IDs, strip internal headers |
| Response aggregation | Combine multiple backend responses | BFF pattern for mobile clients |
| Load balancing | Distribute traffic across instances | Round-robin, least connections, weighted |
| Caching | Cache responses at the edge | Cache GET responses with TTL |
| Circuit breaking | Fail fast when backend is unhealthy | Open circuit after 5 consecutive failures |
| TLS termination | Handle HTTPS at the gateway | Offload TLS from backend services |
### Gateway Topology Patterns
**Pattern 1: Single Gateway**
```text
┌────────┐ ┌──────────────┐ ┌──────────┐
│ Client │────▶│ Gateway │────▶│ Service A│
└────────┘ │ │────▶│ Service B│
│ │────▶│ Service C│
└──────────────┘ └──────────┘
```
Best for: Small teams, <10 services, uniform client needs.
**Pattern 2: Backend-for-Frontend (BFF)**
```text
┌──────────┐ ┌───────────────┐
│ Mobile │────▶│ Mobile BFF │───▶ Services
└──────────┘ └───────────────┘
┌──────────┐ ┌───────────────┐
│ Web │────▶│ Web BFF │───▶ Services
└──────────┘ └───────────────┘
┌──────────┐ ┌───────────────┐
│ Partner │────▶│ Partner API │───▶ Services
│ API │ │ Gateway │
└──────────┘ └───────────────┘
```
Best for: Different client types with distinct data needs.
**Pattern 3: Federated Gateway**
```text
┌────────┐ ┌───────────────┐ ┌──────────────┐
│ Client │────▶│ Edge Gateway │────▶│ Team A GW │───▶ Team A services
└────────┘ │ (auth, rate │────▶│ Team B GW │───▶ Team B services
│ limiting) │────▶│ Team C GW │───▶ Team C services
└───────────────┘ └──────────────┘
```
Best for: Large organizations, multiple teams owning their own gateway configuration.
### Rate Limiting Patterns
```typescript
// Token bucket rate limiting (typical gateway configuration)
// Kong rate-limiting plugin configuration
const rateLimitConfig = {
plugin: 'rate-limiting',
config: {
minute: 60, // 60 requests per minute
hour: 1000, // 1000 requests per hour
policy: 'redis', // Use Redis for distributed counting
fault_tolerant: true, // Allow traffic if Redis is down
hide_client_headers: false,
redis_host: 'redis',
redis_port: 6379,
},
};
// Response headers
// X-RateLimit-Limit: 60
// X-RateLimit-Remaining: 45
// X-RateLimit-Reset: 1640000000
```
| Algorithm | Description | Use When |
|-----------|-------------|----------|
| Token bucket | Tokens replenish at fixed rate, consumed per request | Burst-tolerant, smooth throttling |
| Sliding window | Count requests in a rolling time window | Precise limits, no burst |
| Fixed window | Count requests per fixed time interval | Simple, slight burst at window edges |
| Leaky bucket | Process requests at fixed rate, queue excess | Smooth output rate |
### Request Aggregation
```typescript
// BFF aggregation pattern — single client request, multiple backend calls
app.get('/api/dashboard', async (req, res) => {
const userId = req.user.id;
// Parallel fetch from multiple services
const [profile, orders, notifications, recommendations] = await Promise.all([
userService.getProfile(userId),
orderService.getRecent(userId, { limit: 5 }),
notificationService.getUnread(userId),
recommendationService.getForUser(userId),
]);
// Aggregate into client-optimized response
res.json({
user: { name: profile.name, avatar: profile.avatar },
recentOrders: orders.map(o => ({ id: o.id, status: o.status, total: o.total })),
unreadCount: notifications.length,
recommendations: recommendations.slice(0, 3),
});
});
```
---
## Service Mesh Architecture
### Core Concepts
A service mesh is a dedicated infrastructure layer for service-to-service communication. It uses sidecar proxies deployed alongside each service to handle networking concerns.
```text
┌─────────────────────────────────────────────────┐
│ Control Plane │
│ (Configuration, certificates, policies) │
└───────────┬──────────────┬──────────────┬────────┘
│ │ │
┌──────▼──────┐ ┌────▼────────┐ ┌──▼──────────┐
│ Service A │ │ Service B │ │ Service C │
│ ┌────────┐ │ │ ┌────────┐ │ │ ┌────────┐ │
│ │ App │ │ │ │ App │ │ │ │ App │ │
│ └───┬────┘ │ │ └───┬────┘ │ │ └───┬────┘ │
│ ┌───▼────┐ │ │ ┌───▼────┐ │ │ ┌───▼────┐ │
│ │Sidecar │◄├─┼─▶│Sidecar │◄├─┼─▶│Sidecar │ │
│ │Proxy │ │ │ │Proxy │ │ │ │Proxy │ │
│ └────────┘ │ │ └────────┘ │ │ └────────┘ │
└─────────────┘ └────────────┘ └──────────────┘
Data Plane (proxies handle all traffic)
```
### Sidecar Proxy Responsibilities
| Responsibility | Description |
|---------------|-------------|
| Traffic routing | Route requests based on rules (headers, weight, path) |
| Load balancing | Distribute traffic across service instances |
| mTLS encryption | Encrypt all service-to-service traffic |
| Circuit breaking | Prevent cascading failures |
| Retry and timeout | Automatic retry with configurable backoff |
| Observability | Emit metrics, traces, and access logs |
| Health checking | Active and passive health checks |
| Rate limiting | Per-service or per-route limits |
| Access control | Authorization policies between services |
### Control Plane vs Data Plane
| Component | Control Plane | Data Plane |
|-----------|--------------|------------|
| Role | Configuration and policy distribution | Request processing |
| Components | Istiod, Linkerd control plane | Envoy proxy, Linkerd proxy |
| Scaling | Single instance or HA pair | One per service instance (sidecar) |
| Failure impact | No new config updates, existing config works | Service-to-service traffic affected |
| Resource usage | Low (control only) | Per-pod overhead (CPU, memory, latency) |
---
## Technology Comparison
### Gateway Comparison
| Feature | Kong | AWS API Gateway | Envoy (standalone) | Traefik | NGINX |
|---------|------|----------------|--------------------|---------| ------|
| Deployment | Self-hosted / Cloud | Managed | Self-hosted | Self-hosted | Self-hosted |
| Plugin ecosystem | Large (Lua, Go) | AWS integrations | Filters (C++, Wasm) | Middleware | Modules |
| Rate limiting | Built-in | Built-in | Filter | Middleware | Module |
| Auth | JWT, OAuth, OIDC | IAM, Cognito, Lambda auth | ext_authz filter | ForwardAuth | Auth module |
| Observability | Prometheus, Datadog | CloudWatch | Prometheus, Zipkin | Prometheus | Stub status |
| gRPC support | Yes | Yes | Native | Yes | Yes |
| WebSocket | Yes | Yes | Yes | Yes | Yes |
| Best for | Multi-cloud, plugin needs | AWS-native workloads | High performance, mesh ingress | Docker/K8s auto-discovery | Simple, proven |
### Service Mesh Comparison
| Feature | Istio | Linkerd | AWS App Mesh | Cilium Service Mesh |
|---------|-------|---------|--------------|---------------------|
| Proxy | Envoy | linkerd2-proxy (Rust) | Envoy | eBPF (no sidecar) |
| Complexity | High | Low | Medium | Medium |
| Resource overhead | Higher (Envoy sidecar) | Lower (lightweight proxy) | Medium | Lowest (kernel-level) |
| mTLS | Automatic | Automatic | Manual config | Automatic |
| Multi-cluster | Yes | Yes (limited) | Cross-account | Yes |
| Traffic management | Advanced (fault injection, mirroring) | Basic (split, retry) | Basic | Advanced |
| Observability | Rich (Kiali, Jaeger, Prometheus) | Built-in dashboard | CloudWatch, X-Ray | Hubble |
| Learning curve | Steep | Gentle | Moderate | Moderate |
| Best for | Complex mesh, advanced traffic | Simple mesh, low overhead | AWS-native workloads | High performance, eBPF |
### Selection Quick Guide
```text
Service mesh selection:
├─ < 10 services → No mesh needed. Use library-based patterns.
├─ 10-50 services, want simplicity → Linkerd
├─ 10-50 services, need advanced traffic mgmt → Istio
├─ AWS-native, managed preference → App Mesh
├─ Performance-critical, eBPF available → Cilium
└─ > 50 services, multi-cluster → Istio (with careful tuning)
```
---
## mTLS and Service Identity
### Mutual TLS in Service Mesh
```text
Service A Service B
┌──────────┐ ┌──────────┐
│ │── 1. TLS handshake (client cert) ──▶│ │
│ App │◀─ 2. TLS handshake (server cert) ──│ App │
│ │── 3. Encrypted traffic ────────────▶│ │
└──────────┘ └──────────┘
Both sides present certificates issued by the mesh CA.
Identity is based on service account, not network address.
```
### Identity-Based Authorization
```yaml
# Istio AuthorizationPolicy
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: orders-policy
namespace: production
spec:
selector:
matchLabels:
app: orders-service
rules:
# Allow only payment-service and api-gateway to call orders
- from:
- source:
principals:
- cluster.local/ns/production/sa/payment-service
- cluster.local/ns/production/sa/api-gateway
to:
- operation:
methods: ["GET", "POST"]
paths: ["/api/orders/*"]
# Deny everything else (implicit deny)
```
### Certificate Management
| Approach | Description | Complexity |
|----------|-------------|------------|
| Mesh-managed CA | Mesh control plane issues and rotates certs | Low (automatic) |
| External CA (Vault) | HashiCorp Vault issues certs, mesh distributes | Medium |
| SPIFFE/SPIRE | Standard identity framework, pluggable CAs | Medium-High |
| Manual certs | Team manages certs manually | High (do not do this) |
**Recommended:** Use mesh-managed CA for most deployments. Integrate with external CA (Vault, AWS ACM PCA) for enterprise compliance requirements.
---
## Observability Through Mesh
### Distributed Tracing
Service mesh proxies automatically inject trace headers and emit spans.
```text
Client → [Gateway span] → [Service A span] → [Service B span] → [Database span]
[Service C span]
Each proxy adds its own span without application code changes.
```
**Trace header propagation:**
| Header | Standard | Used By |
|--------|----------|---------|
| `traceparent` | W3C Trace Context | OpenTelemetry, modern systems |
| `x-request-id` | De facto | Envoy, Istio |
| `x-b3-traceid` | Zipkin B3 | Zipkin, older Istio |
### Mesh-Level Metrics
Standard metrics emitted by sidecar proxies (no application instrumentation needed):
| Metric | Description | Alert On |
|--------|-------------|----------|
| `request_count` | Total requests per service/route | Unexpected traffic drops |
| `request_duration` | Latency histogram (P50, P95, P99) | P99 > SLO threshold |
| `response_code` | Count by status code (2xx, 4xx, 5xx) | 5xx rate > 0.1% |
| `tcp_connections` | Active TCP connections | Approaching connection limits |
| `retry_count` | Automatic retries triggered | High retry rate = unhealthy upstream |
### Golden Signals Dashboard
```text
For each service, track:
1. Latency — P50, P95, P99 response time
2. Traffic — Requests per second
3. Errors — 5xx rate as percentage of total
4. Saturation — CPU, memory, connection pool usage
Service mesh provides signals 1-3 automatically.
Signal 4 requires application-level metrics.
```
### Service Topology Visualization
Mesh provides automatic service dependency mapping:
```text
Tools:
- Kiali (Istio) — Service graph, health status, traffic flow
- Linkerd Viz — Dashboard with golden metrics per service
- Hubble (Cilium) — Network flow visibility
- Jaeger/Tempo — Distributed trace visualization
```
---
## Gateway vs Mesh vs Both
### Comparison Matrix
| Concern | API Gateway | Service Mesh | Both (Recommended) |
|---------|-------------|-------------|-------------------|
| North-south traffic (client → service) | Primary role | Not designed for | Gateway handles |
| East-west traffic (service → service) | Not designed for | Primary role | Mesh handles |
| External authentication | Yes | No | Gateway handles |
| Service-to-service auth (mTLS) | No | Yes | Mesh handles |
| Public rate limiting | Yes | No | Gateway handles |
| Internal circuit breaking | Limited | Yes | Mesh handles |
| External API versioning | Yes | No | Gateway handles |
| Internal traffic splitting | No | Yes | Mesh handles |
| TLS termination (external) | Yes | No | Gateway handles |
| mTLS (internal) | No | Yes | Mesh handles |
### Recommended Architecture
```text
┌──────────────┐
│ Internet │
└──────┬───────┘
┌──────▼───────┐ ← North-south boundary
│ API Gateway │ Auth, rate limiting, TLS termination, routing
│ (Kong/Envoy) │
└──────┬───────┘
┌──────▼───────────────────────────────┐
│ Service Mesh (Istio/Linkerd) │ ← East-west boundary
│ │ mTLS, retries, circuit breaking,
│ ┌─────┐ ┌─────┐ ┌─────┐ │ observability, traffic management
│ │Svc A│◄─▶│Svc B│◄─▶│Svc C│ │
│ └─────┘ └─────┘ └─────┘ │
└──────────────────────────────────────┘
```
### When You Do NOT Need a Service Mesh
| Scenario | Why No Mesh |
|----------|-------------|
| < 10 services | Overhead exceeds benefit |
| Single team, single repo | Library-based patterns suffice |
| Serverless architecture | Functions are too short-lived for sidecars |
| Low traffic internal tools | Complexity not justified |
| Early-stage startup | Focus on product, not infrastructure |
**Alternatives to mesh for small deployments:**
- Library-based retries and circuit breaking (p-retry, opossum)
- Application-level mTLS (cert-manager + application config)
- OpenTelemetry SDK for observability (no mesh needed)
---
## Implementation Patterns
### Canary Deployment via Mesh
```yaml
# Istio: Route 95% to v1, 5% to v2
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: orders
spec:
hosts:
- orders
http:
- route:
- destination:
host: orders
subset: v1
weight: 95
- destination:
host: orders
subset: v2
weight: 5
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: orders
spec:
host: orders
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
```
### Retry and Timeout Configuration
```yaml
# Istio retry policy
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: orders
spec:
hosts:
- orders
http:
- timeout: 3s
retries:
attempts: 3
perTryTimeout: 1s
retryOn: 5xx,reset,connect-failure,retriable-4xx
route:
- destination:
host: orders
```
### Circuit Breaker Configuration
```yaml
# Istio circuit breaker
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: orders
spec:
host: orders
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
http1MaxPendingRequests: 100
http2MaxRequests: 1000
maxRequestsPerConnection: 10
outlierDetection:
consecutive5xxErrors: 5
interval: 10s
baseEjectionTime: 30s
maxEjectionPercent: 50
```
---
## Anti-Patterns
### 1. Mesh for Everything
```text
[FAIL] Deploying a service mesh for 3 services because "everyone uses Istio"
→ Massive operational overhead for minimal benefit
[PASS] Start with library-based patterns. Adopt mesh when you have
10+ services and measurable networking pain.
```
### 2. Gateway as Service Bus
```text
[FAIL] Putting business logic, data transformation, and orchestration in the gateway
→ Gateway becomes a bottleneck and single point of failure for logic
[PASS] Gateway handles cross-cutting concerns only (auth, rate limiting, routing).
Business logic stays in services.
```
### 3. Ignoring Sidecar Resource Overhead
```text
[FAIL] Deploying mesh without accounting for sidecar CPU/memory per pod
→ Resource exhaustion, unexpected costs, latency increase
[PASS] Budget 50-128MB memory and 0.1-0.5 CPU per sidecar proxy.
Monitor mesh overhead as a first-class metric.
```
### 4. No Mesh Bypass for Debugging
```text
[FAIL] No way to bypass the mesh for troubleshooting
→ Cannot isolate whether issues are mesh-related or application-related
[PASS] Maintain ability to disable sidecar injection per namespace or pod.
Have runbooks for mesh-bypass debugging.
```
### 5. mTLS Without Identity Policies
```text
[FAIL] Enabling mTLS but no authorization policies → all services can call all services
→ mTLS only encrypts traffic, it does not authorize
[PASS] Pair mTLS with explicit AuthorizationPolicy rules.
Default deny, explicit allow per service pair.
```
---
## Decision Framework
### Do You Need an API Gateway?
```text
1. Do you expose APIs to external clients? [Yes → You need a gateway]
2. Do you need centralized auth for external traffic? [Yes → Gateway]
3. Do you need rate limiting for public APIs? [Yes → Gateway]
4. Do you have multiple BFF needs (mobile, web, partner)? [Yes → Multiple gateways]
5. Internal-only services? [Gateway optional, mesh sufficient]
```
### Do You Need a Service Mesh?
```text
1. How many services? [< 10 → No, 10-50 → Maybe, > 50 → Yes]
2. Do you need mTLS between services? [Yes → +2]
3. Do you need advanced traffic management? [Yes → +2]
4. Is observability a gap today? [Yes → +1]
5. Does the team have K8s experience? [Yes → +1, No → -2]
6. Are you running on Kubernetes? [Yes → +1, No → -2]
Score: 0-2 → Library-based patterns
Score: 3-4 → Linkerd (simpler mesh)
Score: 5+ → Istio or Cilium (full mesh)
```
### Gateway Selection
```text
Choosing a gateway:
├─ AWS-native, managed preference → AWS API Gateway
├─ Multi-cloud, plugin extensibility → Kong
├─ Performance-critical, already using Envoy → Envoy as gateway
├─ Kubernetes auto-discovery → Traefik
├─ Simple reverse proxy, proven → NGINX
└─ GraphQL federation → Apollo Router
```
---
## Cross-References
- [modern-patterns.md](modern-patterns.md) Service mesh and microservices overview
- [scalability-reliability-guide.md](scalability-reliability-guide.md) Load balancing, circuit breakers, resilience
- [migration-modernization-guide.md](migration-modernization-guide.md) Strangler fig pattern with gateway routing
- [data-architecture-patterns.md](data-architecture-patterns.md) Service-to-service data patterns
- [../software-backend/SKILL.md](../software-backend/SKILL.md) Backend service implementation
- [../../ops-devops-platform/SKILL.md](../../ops-devops-platform/SKILL.md) Kubernetes, CI/CD, deployment strategies
- [../../software-security-appsec/SKILL.md](../../software-security-appsec/SKILL.md) Zero-trust security, mTLS