1. Microservices Architecture Overview
1.1. Monolith vs Microservices
Monolithic Architecture:
┌────────────────────────────────┐
│ Single Application │
│ ┌──────────────────────────┐ │
│ │ Web Layer │ │
│ ├──────────────────────────┤ │
│ │ Business Logic │ │
│ ├──────────────────────────┤ │
│ │ Data Access │ │
│ └──────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Database │ │
│ └──────────────┘ │
└────────────────────────────────┘
Microservices Architecture:
┌──────────────┐
│ API Gateway │
│ (Nginx) │
└──────┬───────┘
│
┌──────────────────┼──────────────────┐
│ │ │
┌───▼───┐ ┌───▼───┐ ┌───▼───┐
│ User │ │Order │ │Product│
│Service│ │Service│ │Service│
└───┬───┘ └───┬───┘ └───┬───┘
│ │ │
┌───▼───┐ ┌───▼───┐ ┌───▼───┐
│User DB│ │Order │ │Product│
│ │ │ DB │ │ DB │
└───────┘ └───────┘ └───────┘
1.2. API Gateway Pattern
# API Gateway configuration http { # Service discovery (will be populated dynamically) upstream user_service { server user-service-1:8081; server user-service-2:8081; server user-service-3:8081; keepalive 32; }upstream order_service { server order-service-1:8082; server order-service-2:8082; keepalive 32; } upstream product_service { server product-service-1:8083; server product-service-2:8083; keepalive 32; } upstream payment_service { server payment-service-1:8084; keepalive 16; } # Rate limiting per service limit_req_zone $binary_remote_addr zone=user_limit:10m rate=100r/s; limit_req_zone $binary_remote_addr zone=order_limit:10m rate=50r/s; limit_req_zone $binary_remote_addr zone=product_limit:10m rate=200r/s; limit_req_zone $binary_remote_addr zone=payment_limit:10m rate=10r/s; server { listen 80; server_name api.example.com; # Global headers add_header X-Gateway "nginx-api-gateway" always; # User service location /api/users { limit_req zone=user_limit burst=20 nodelay; proxy_pass http://user_service; include includes/proxy_params.conf; include includes/timeout_params.conf; } # Order service location /api/orders { limit_req zone=order_limit burst=10 nodelay; proxy_pass http://order_service; include includes/proxy_params.conf; include includes/timeout_params.conf; } # Product service location /api/products { limit_req zone=product_limit burst=50 nodelay; proxy_pass http://product_service; include includes/proxy_params.conf; include includes/timeout_params.conf; } # Payment service (stricter limits) location /api/payments { limit_req zone=payment_limit burst=5; limit_conn addr 5; proxy_pass http://payment_service; include includes/proxy_params.conf; # Longer timeout for payments proxy_read_timeout 60s; } # Health check aggregation location /health { access_log off; content_by_lua_block { local http = require "resty.http" local cjson = require "cjson" local services = { {name = "user", url = "http://user-service-1:8081/health"}, {name = "order", url = "http://order-service-1:8082/health"}, {name = "product", url = "http://product-service-1:8083/health"}, {name = "payment", url = "http://payment-service-1:8084/health"} } local results = {} local all_healthy = true for _, service in ipairs(services) do local httpc = http.new() local res, err = httpc:request_uri(service.url, { method = "GET", keepalive_timeout = 60000, keepalive_pool = 10 }) if res and res.status == 200 then results[service.name] = "healthy" else results[service.name] = "unhealthy" all_healthy = false end end ngx.status = all_healthy and 200 or 503 ngx.say(cjson.encode(results)) } } }
}
Include files:
# /etc/nginx/includes/proxy_params.conf proxy_http_version 1.1; proxy_set_header Connection "";proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Request-ID $request_id;
Add tracing headers
proxy_set_header X-B3-TraceId $request_id; proxy_set_header X-B3-SpanId $request_id;
# /etc/nginx/includes/timeout_params.conf proxy_connect_timeout 5s; proxy_send_timeout 10s; proxy_read_timeout 30s;
proxy_next_upstream error timeout http_502 http_503 http_504; proxy_next_upstream_tries 2; proxy_next_upstream_timeout 10s;
1.3. Service Mesh Benefits
Without Service Mesh:
Service A → Service B (manual retries, timeouts in code)
Service A → Service C (manual circuit breaker)
Service B → Service D (manual tracing)
With Service Mesh:
Service A → Sidecar → Sidecar → Service B
↓ ↓ ↓ ↓
Logic Retries Tracing Circuit Breaker
2. Service Discovery
2.1. Static Configuration
# Simple static upstream upstream user_service { server 10.0.1.10:8080; server 10.0.1.11:8080; server 10.0.1.12:8080; }Problems:
- Manual updates required
- No dynamic scaling
- Hard to manage in cloud environments
2.2. DNS-based Service Discovery
# DNS-based discovery upstream user_service { # Resolve DNS on each request server user-service.internal:8080 resolve;# Or with resolver directive # resolver 10.0.0.2 valid=10s;}
http { resolver 10.0.0.2 valid=10s; resolver_timeout 5s;
upstream dynamic_backend { zone backend 64k; server backend.internal:8080 resolve; }
}
2.3. Consul Service Discovery
Install Consul:
# Download Consul wget https://releases.hashicorp.com/consul/1.17.0/consul_1.17.0_linux_amd64.zip unzip consul_1.17.0_linux_amd64.zip sudo mv consul /usr/local/bin/Start Consul agent
consul agent -dev
Register services with Consul:
// user-service.json
{
"service": {
"name": "user-service",
"tags": ["v1", "production"],
"port": 8080,
"check": {
"http": "http://localhost:8080/health",
"interval": "10s",
"timeout": "1s"
}
}
}
# Register service
consul services register user-service.json
Nginx with Consul Template:
# Install Consul Template
wget https://releases.hashicorp.com/consul-template/0.34.0/consul-template_0.34.0_linux_amd64.zip
unzip consul-template_0.34.0_linux_amd64.zip
sudo mv consul-template /usr/local/bin/
Template file:
# /etc/nginx/templates/upstream.conf.ctmpl {{range services}} upstream {{.Name}} { zone {{.Name}} 64k; {{range service .Name}} server {{.Address}}:{{.Port}} max_fails=3 fail_timeout=30s; {{end}} keepalive 32; } {{end}}server { listen 80;
{{range services}} location /api/{{.Name}} { proxy_pass http://{{.Name}}; include /etc/nginx/includes/proxy_params.conf; } {{end}}
}
Run Consul Template:
consul-template
-template "/etc/nginx/templates/upstream.conf.ctmpl:/etc/nginx/conf.d/upstream.conf:nginx -s reload"
-consul-addr "localhost:8500"
Systemd service:
# /etc/systemd/system/consul-template.service [Unit] Description=Consul Template Requires=network-online.target After=network-online.target[Service] Type=simple User=nginx Group=nginx ExecStart=/usr/local/bin/consul-template
-template "/etc/nginx/templates/upstream.conf.ctmpl:/etc/nginx/conf.d/upstream.conf:nginx -s reload"
-consul-addr "localhost:8500" ExecReload=/bin/kill -HUP $MAINPID KillMode=process Restart=on-failure RestartSec=10s
[Install] WantedBy=multi-user.target
2.4. Kubernetes Service Discovery
# kubernetes-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-gateway
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
host: api.example.com http: paths:- path: /api/users pathType: Prefix backend: service: name: user-service port: number: 8080
- path: /api/orders pathType: Prefix backend: service: name: order-service port: number: 8080
path: /api/products pathType: Prefix backend: service: name: product-service port: number: 8080
3. Circuit Breaker Pattern
3.1. Basic Circuit Breaker
# Circuit breaker with passive health checks upstream backend { server backend1.example.com:8080 max_fails=3 fail_timeout=30s; server backend2.example.com:8080 max_fails=3 fail_timeout=30s; server backend3.example.com:8080 max_fails=3 fail_timeout=30s; }server { location /api/ { proxy_pass http://backend;
# Circuit breaker behavior proxy_next_upstream error timeout http_502 http_503 http_504; proxy_next_upstream_tries 2; proxy_next_upstream_timeout 5s; # If all backends fail, return cached response proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; # Timeouts proxy_connect_timeout 2s; proxy_read_timeout 5s; }
}
3.2. Advanced Circuit Breaker with Lua
http { lua_shared_dict circuit_breaker 10m;init_by_lua_block { -- Circuit breaker configuration circuit_breaker = { threshold = 5, -- Open after 5 failures timeout = 30, -- Try again after 30s half_open_requests = 1 -- Allow 1 request when half-open } } server { location /api/payment { access_by_lua_block { local cb = ngx.shared.circuit_breaker local key = "payment_service" -- Get circuit state local failures = cb:get(key .. ":failures") or 0 local state = cb:get(key .. ":state") or "closed" local last_failure = cb:get(key .. ":last_failure") or 0 -- Check if circuit is open if state == "open" then local now = ngx.now() if now - last_failure < circuit_breaker.timeout then ngx.status = 503 ngx.say("Circuit breaker is open") return ngx.exit(503) else -- Move to half-open cb:set(key .. ":state", "half-open") state = "half-open" end end -- Half-open: allow limited requests if state == "half-open" then local half_open_count = cb:incr(key .. ":half_open_count", 1, 0) if half_open_count > circuit_breaker.half_open_requests then ngx.status = 503 ngx.say("Circuit breaker is half-open, try again") return ngx.exit(503) end end } proxy_pass http://payment_service; log_by_lua_block { local cb = ngx.shared.circuit_breaker local key = "payment_service" local status = ngx.status if status >= 500 then -- Increment failure count local failures = cb:incr(key .. ":failures", 1, 0) cb:set(key .. ":last_failure", ngx.now()) -- Open circuit if threshold reached if failures >= circuit_breaker.threshold then cb:set(key .. ":state", "open") ngx.log(ngx.ERR, "Circuit breaker opened for " .. key) end else -- Success - reset or close circuit local state = cb:get(key .. ":state") if state == "half-open" then cb:set(key .. ":state", "closed") cb:set(key .. ":failures", 0) cb:set(key .. ":half_open_count", 0) ngx.log(ngx.INFO, "Circuit breaker closed for " .. key) elseif state == "closed" then cb:set(key .. ":failures", 0) end end } } }
}
3.3. Circuit Breaker Monitoring
server { listen 8080;location /circuit-breaker/status { access_log off; content_by_lua_block { local cb = ngx.shared.circuit_breaker local cjson = require "cjson" local services = {"payment_service", "order_service", "user_service"} local status = {} for _, service in ipairs(services) do status[service] = { state = cb:get(service .. ":state") or "closed", failures = cb:get(service .. ":failures") or 0, last_failure = cb:get(service .. ":last_failure") or 0 } end ngx.say(cjson.encode(status)) } }
}
4. Retry Policies
4.1. Basic Retry Configuration
upstream backend { server backend1.example.com:8080; server backend2.example.com:8080; server backend3.example.com:8080; }server { location /api/ { proxy_pass http://backend;
# Retry on these conditions proxy_next_upstream error timeout http_502 http_503 http_504; # Maximum retry attempts proxy_next_upstream_tries 3; # Total timeout for all retries proxy_next_upstream_timeout 10s; # Connection timeout proxy_connect_timeout 2s; proxy_send_timeout 5s; proxy_read_timeout 5s; }
}
4.2. Exponential Backoff
http { lua_shared_dict retry_state 10m;server { location /api/with-backoff { rewrite_by_lua_block { local retry_state = ngx.shared.retry_state local key = ngx.var.request_id local attempt = retry_state:incr(key, 1, 0) if attempt > 1 then -- Exponential backoff: 2^(attempt-1) * 100ms local delay = math.pow(2, attempt - 1) * 0.1 ngx.sleep(delay) end -- Max 3 attempts if attempt > 3 then ngx.status = 503 ngx.say("Max retries exceeded") return ngx.exit(503) end } proxy_pass http://backend; log_by_lua_block { local retry_state = ngx.shared.retry_state local key = ngx.var.request_id -- Clean up on success if ngx.status < 500 then retry_state:delete(key) end } } }
}
4.3. Retry Budget
http { lua_shared_dict retry_budget 10m;init_by_lua_block { -- Allow 10% of requests to be retries retry_budget_limit = 0.1 } server { location /api/ { access_by_lua_block { local budget = ngx.shared.retry_budget -- Get counters local total = budget:get("total_requests") or 0 local retries = budget:get("total_retries") or 0 -- Check if this is a retry local is_retry = ngx.var.arg_retry == "1" if is_retry then local retry_ratio = retries / (total + 1) if retry_ratio >= retry_budget_limit then ngx.status = 503 ngx.say("Retry budget exceeded") return ngx.exit(503) end budget:incr("total_retries", 1, 0) end budget:incr("total_requests", 1, 0) } proxy_pass http://backend; } }
}
5. Rate Limiting per Service
5.1. Service-specific Rate Limits
http { # Different limits for different services limit_req_zone $binary_remote_addr zone=user_svc:10m rate=100r/s; limit_req_zone $binary_remote_addr zone=order_svc:10m rate=50r/s; limit_req_zone $binary_remote_addr zone=product_svc:10m rate=200r/s; limit_req_zone $binary_remote_addr zone=payment_svc:10m rate=10r/s; limit_req_zone $binary_remote_addr zone=admin_svc:10m rate=5r/s;server { listen 80; # User service - high limit location /api/users { limit_req zone=user_svc burst=200 nodelay; proxy_pass http://user_service; } # Order service - medium limit location /api/orders { limit_req zone=order_svc burst=100 nodelay; proxy_pass http://order_service; } # Product service - highest limit (read-heavy) location /api/products { limit_req zone=product_svc burst=400 nodelay; proxy_pass http://product_service; } # Payment service - strict limit (critical) location /api/payments { limit_req zone=payment_svc burst=5; limit_conn addr 3; proxy_pass http://payment_service; } # Admin service - very strict location /api/admin { limit_req zone=admin_svc burst=2; limit_conn addr 1; # Also require auth auth_basic "Admin Area"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://admin_service; } }
}
5.2. Per-user Rate Limiting
http { # Extract user ID from JWT or cookie map $http_authorization $user_id { default "anonymous"; ~*Bearer\s+([A-Za-z0-9-_.]+) $1; }# Rate limit by user ID limit_req_zone $user_id zone=per_user:10m rate=50r/s; # Different limits for different user tiers map $user_id $user_tier { default "free"; ~*premium_ "premium"; ~*enterprise_ "enterprise"; } map $user_tier $rate_limit_zone { free per_user_free; premium per_user_premium; enterprise per_user_enterprise; } limit_req_zone $user_id zone=per_user_free:10m rate=10r/s; limit_req_zone $user_id zone=per_user_premium:10m rate=50r/s; limit_req_zone $user_id zone=per_user_enterprise:10m rate=200r/s; server { location /api/ { # Apply rate limit based on user tier limit_req zone=$rate_limit_zone burst=20 nodelay; proxy_pass http://backend; # Add rate limit info to response add_header X-RateLimit-Tier $user_tier; } }
}
5.3. Token Bucket Algorithm
http { lua_shared_dict token_bucket 10m;server { location /api/ { access_by_lua_block { local tb = ngx.shared.token_bucket local user_id = ngx.var.http_x_user_id or ngx.var.remote_addr -- Token bucket configuration local capacity = 100 -- Max tokens local refill_rate = 10 -- Tokens per second -- Get current state local key = "tb:" .. user_id local tokens = tb:get(key .. ":tokens") or capacity local last_refill = tb:get(key .. ":last_refill") or ngx.now() -- Refill tokens local now = ngx.now() local time_passed = now - last_refill local new_tokens = math.min(capacity, tokens + (time_passed * refill_rate)) -- Check if request allowed if new_tokens >= 1 then -- Allow request tb:set(key .. ":tokens", new_tokens - 1) tb:set(key .. ":last_refill", now) -- Add headers ngx.header["X-RateLimit-Remaining"] = math.floor(new_tokens - 1) ngx.header["X-RateLimit-Limit"] = capacity else -- Rate limited ngx.status = 429 ngx.header["Retry-After"] = math.ceil((1 - new_tokens) / refill_rate) ngx.say("Rate limit exceeded") return ngx.exit(429) end } proxy_pass http://backend; } }
}
6. Distributed Tracing
6.1. OpenTelemetry Integration
http { # Generate unique request ID map $request_id $trace_id { default $request_id; }log_format trace '$remote_addr - [$time_local] "$request" ' '$status $body_bytes_sent ' 'trace_id=$trace_id ' 'span_id=$request_id ' 'parent_span=$http_x_parent_span ' 'service=api-gateway ' 'duration=$request_time'; access_log /var/log/nginx/trace.log trace; server { listen 80; location /api/ { # Add tracing headers proxy_set_header X-Trace-ID $trace_id; proxy_set_header X-Span-ID $request_id; proxy_set_header X-Parent-Span $request_id; # Service name proxy_set_header X-Service-Name "api-gateway"; proxy_pass http://backend; } }
}
6.2. Jaeger Integration
http { lua_shared_dict tracing 10m;init_by_lua_block { local jaeger = require "jaeger" tracer = jaeger.new_tracer("nginx-gateway", { sampler = { type = "const", param = 1 -- Sample all requests }, reporter = { endpoint = "http://jaeger:14268/api/traces" } }) } server { location /api/ { access_by_lua_block { local span = tracer:start_span("nginx-gateway") span:set_tag("http.method", ngx.var.request_method) span:set_tag("http.url", ngx.var.request_uri) span:set_tag("http.host", ngx.var.host) -- Store span for later ngx.ctx.span = span } proxy_pass http://backend; # Forward trace context proxy_set_header uber-trace-id $http_uber_trace_id; log_by_lua_block { local span = ngx.ctx.span if span then span:set_tag("http.status_code", ngx.status) span:finish() end } } }
}
6.3. Zipkin Integration
http { # Zipkin headers map $http_x_b3_traceid $trace_id { default $request_id; ~.+ $http_x_b3_traceid; }map $http_x_b3_spanid $span_id { default $request_id; ~.+ $http_x_b3_spanid; } server { location /api/ { # B3 propagation headers proxy_set_header X-B3-TraceId $trace_id; proxy_set_header X-B3-SpanId $span_id; proxy_set_header X-B3-ParentSpanId $span_id; proxy_set_header X-B3-Sampled "1"; proxy_pass http://backend; # Log tracing info access_log /var/log/nginx/trace.log; } }
}
7. Service Mesh Integration
7.1. Istio Sidecar Pattern
Kubernetes deployment with Istio:
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
spec:
replicas: 3
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
version: v1
annotations:
sidecar.istio.io/inject: "true"
spec:
containers:
- name: user-service
image: user-service:v1
ports:
- containerPort: 8080
Istio VirtualService:
# virtualservice.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: user-service
spec:
hosts:
- user-service http:
- match:
- headers: x-user-tier: exact: premium route:
- destination: host: user-service subset: v2 weight: 100
route:- destination: host: user-service subset: v1 weight: 90
destination: host: user-service subset: v2 weight: 10
Istio DestinationRule:
# destinationrule.yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: user-service
spec:
host: user-service
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
http1MaxPendingRequests: 50
http2MaxRequests: 100
maxRequestsPerConnection: 2
loadBalancer:
simple: LEAST_REQUEST
outlierDetection:
consecutiveErrors: 5
interval: 30s
baseEjectionTime: 30s
maxEjectionPercent: 50
subsets:
name: v1
labels:
version: v1
name: v2
labels:
version: v2
7.2. Consul Connect
Service definition with Connect:
{
"service": {
"name": "user-service",
"port": 8080,
"connect": {
"sidecar_service": {
"port": 20000,
"proxy": {
"upstreams": [
{
"destination_name": "order-service",
"local_bind_port": 8081
},
{
"destination_name": "product-service",
"local_bind_port": 8082
}
],
"config": {
"protocol": "http",
"local_request_timeout_ms": 5000
}
}
}
}
}
}
Nginx with Consul Connect:
upstream order_service {Connect to Consul Connect sidecar
server 127.0.0.1:8081; keepalive 32; }upstream product_service { server 127.0.0.1:8082; keepalive 32; }
server { listen 8080;
location /api/orders { proxy_pass http://order_service; } location /api/products { proxy_pass http://product_service; }
}
7.3. Linkerd Integration
Linkerd proxy injection:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-gateway
annotations:
linkerd.io/inject: enabled
spec:
replicas: 2
selector:
matchLabels:
app: nginx-gateway
template:
metadata:
labels:
app: nginx-gateway
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
Service profile for retry budget:
apiVersion: linkerd.io/v1alpha2
kind: ServiceProfile
metadata:
name: user-service
spec:
routes:
name: GET /api/users condition: method: GET pathRegex: /api/users/.* responseClasses:condition: status: min: 500 max: 599 isFailure: true retries: limit: 3 budget: minRetriesPerSecond: 10 ttl: 10s retryRatio: 0.2
8. Canary Deployments
8.1. Basic Canary with Weight
upstream user_service_v1 { server user-v1-1:8080; server user-v1-2:8080; }upstream user_service_v2 { server user-v2-1:8080; server user-v2-2:8080; }
Split clients based on IP
split_clients "${remote_addr}" $version { 90% "v1"; 10% "v2"; }
server { location /api/users { if ($version = "v1") { proxy_pass http://user_service_v1; }
if ($version = "v2") { proxy_pass http://user_service_v2; } add_header X-Version $version; }
}
8.2. Header-based Canary
# Route by header map $http_x_canary $backend { default user_service_v1; "true" user_service_v2; }upstream user_service_v1 { server user-v1:8080; }
upstream user_service_v2 { server user-v2:8080; }
server { location /api/users { proxy_pass http://$backend; add_header X-Backend $backend; } }
Usage:
Normal: curl http://api.example.com/api/users
Canary: curl -H "X-Canary: true" http://api.example.com/api/users
8.3. Progressive Canary Rollout
# Gradually increase canary traffic map $time_iso8601 $canary_percentage { ~2024-01-01 10; ~2024-01-02 25; ~2024-01-03 50; ~2024-01-04 75; default 100; }split_clients "${remote_addr}${http_user_agent}" $version { ${canary_percentage}% "v2"; * "v1"; }
server { location /api/users { if ($version = "v1") { proxy_pass http://user_service_v1; }
if ($version = "v2") { proxy_pass http://user_service_v2; } }
}
8.4. Feature Flag-based Canary
http { lua_shared_dict feature_flags 10m;init_by_lua_block { local ff = ngx.shared.feature_flags ff:set("new_ui_enabled", "false") ff:set("new_ui_percentage", 10) } server { location /api/users { access_by_lua_block { local ff = ngx.shared.feature_flags local enabled = ff:get("new_ui_enabled") local percentage = ff:get("new_ui_percentage") or 0 if enabled == "true" then -- Random selection based on percentage local random = math.random(100) if random <= percentage then ngx.var.backend = "user_service_v2" else ngx.var.backend = "user_service_v1" end else ngx.var.backend = "user_service_v1" end } proxy_pass http://$backend; } # Feature flag management endpoint location /admin/feature-flags { content_by_lua_block { local ff = ngx.shared.feature_flags local cjson = require "cjson" if ngx.req.get_method() == "GET" then local flags = { new_ui_enabled = ff:get("new_ui_enabled"), new_ui_percentage = ff:get("new_ui_percentage") } ngx.say(cjson.encode(flags)) elseif ngx.req.get_method() == "POST" then ngx.req.read_body() local data = cjson.decode(ngx.req.get_body_data()) if data.new_ui_enabled then ff:set("new_ui_enabled", data.new_ui_enabled) end if data.new_ui_percentage then ff:set("new_ui_percentage", data.new_ui_percentage) end ngx.say("Feature flags updated") end } } }
}
9. Blue-Green Deployments
9.1. Basic Blue-Green Setup
# Blue environment (current production) upstream blue_env { server blue-1:8080; server blue-2:8080; server blue-3:8080; }Green environment (new version)
upstream green_env { server green-1:8080; server green-2:8080; server green-3:8080; }
Active environment
map $http_host $active_env { default blue_env; }
server { listen 80;
location / { proxy_pass http://$active_env; add_header X-Environment $active_env; }
}
Switch script:
#!/bin/bashswitch_environment.sh
CURRENT=$(curl -s http://localhost/env)
if [ "$CURRENT" == "blue" ]; then NEW="green" else NEW="blue" fi
Update configuration
sed -i "s/default blue_env/default ${NEW}_env/" /etc/nginx/nginx.conf
Test configuration
nginx -t
if [ $? -eq 0 ]; then # Reload Nginx nginx -s reload echo "Switched to $NEW environment" else echo "Configuration test failed, rollback" sed -i "s/default ${NEW}_env/default ${CURRENT}_env/" /etc/nginx/nginx.conf fi
9.2. Blue-Green with Traffic Shaping
# Gradual cutover split_clients "${remote_addr}" $environment { 75% "blue_env"; # Old version gets 75% 25% "green_env"; # New version gets 25% }server { location / { proxy_pass http://$environment; add_header X-Environment $environment; } }
After validation, switch to 100% green
Then update:
split_clients "${remote_addr}" $environment {
0% "blue_env";
100% "green_env";
}
9.3. Blue-Green with Smoke Tests
server { # Production traffic location / { proxy_pass http://$active_env; }# Smoke test endpoint for green location /test/green { proxy_pass http://green_env; # Only allow from internal network allow 10.0.0.0/8; deny all; add_header X-Test-Environment "green"; }
}
Automated smoke test:
#!/bin/bashsmoke_test.sh
GREEN_URL="http://localhost/test/green" TESTS=( "/health" "/api/users" "/api/products" )
echo "Running smoke tests on green environment..."
FAILED=0 for test in "${TESTS[@]}"; do URL="${GREEN_URL}${test}" STATUS=$(curl -s -o /dev/null -w "%{http_code}" $URL)
if [ $STATUS -eq 200 ]; then echo "✓ PASS: $test" else echo "✗ FAIL: $test (Status: $STATUS)" FAILED=1 fidone
if [ $FAILED -eq 0 ]; then echo "All smoke tests passed. Ready to switch." exit 0 else echo "Smoke tests failed. Do not switch." exit 1 fi
10. Complete Microservices Example
10.1. Full API Gateway Configuration
# /etc/nginx/nginx.confuser nginx; worker_processes auto; worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid;
events { worker_connections 4096; use epoll; multi_accept on; }
http { include /etc/nginx/mime.types; default_type application/octet-stream;
# Logging log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; log_format trace '$remote_addr - [$time_local] "$request" ' '$status $body_bytes_sent ' 'trace_id=$request_id ' 'upstream=$upstream_addr ' 'upstream_time=$upstream_response_time ' 'request_time=$request_time'; access_log /var/log/nginx/access.log main; access_log /var/log/nginx/trace.log trace; # Performance settings sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; server_tokens off; # Gzip gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss; # Rate limiting zones limit_req_zone $binary_remote_addr zone=global:10m rate=1000r/s; limit_req_zone $binary_remote_addr zone=user_svc:10m rate=100r/s; limit_req_zone $binary_remote_addr zone=order_svc:10m rate=50r/s; limit_req_zone $binary_remote_addr zone=payment_svc:10m rate=10r/s; # Connection limiting limit_conn_zone $binary_remote_addr zone=addr:10m; # Upstreams include /etc/nginx/conf.d/upstreams/*.conf; # Servers include /etc/nginx/conf.d/servers/*.conf;
}
Upstreams configuration:
# /etc/nginx/conf.d/upstreams/services.confupstream user_service { least_conn; server user-1.internal:8080 max_fails=3 fail_timeout=30s; server user-2.internal:8080 max_fails=3 fail_timeout=30s; server user-3.internal:8080 max_fails=3 fail_timeout=30s; keepalive 64; }
upstream order_service { least_conn; server order-1.internal:8080 max_fails=3 fail_timeout=30s; server order-2.internal:8080 max_fails=3 fail_timeout=30s; keepalive 32; }
upstream product_service { least_conn; server product-1.internal:8080 max_fails=3 fail_timeout=30s; server product-2.internal:8080 max_fails=3 fail_timeout=30s; server product-3.internal:8080 max_fails=3 fail_timeout=30s; keepalive 64; }
upstream payment_service { server payment-1.internal:8080 max_fails=2 fail_timeout=10s; server payment-2.internal:8080 max_fails=2 fail_timeout=10s backup; keepalive 16; }
Server configuration:
# /etc/nginx/conf.d/servers/api-gateway.confserver { listen 80; listen [::]:80; server_name api.example.com; return 301 https://$server_name$request_uri; }
server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name api.example.com;
# SSL ssl_certificate /etc/nginx/ssl/cert.pem; ssl_certificate_key /etc/nginx/ssl/key.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # Security headers add_header Strict-Transport-Security "max-age=31536000" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; # Global rate limit limit_req zone=global burst=2000 nodelay; limit_conn addr 50; # Health check location /health { access_log off; return 200 "OK\n"; add_header Content-Type text/plain; } # User service location /api/v1/users { limit_req zone=user_svc burst=200 nodelay; proxy_pass http://user_service/users; include /etc/nginx/includes/proxy.conf; include /etc/nginx/includes/tracing.conf; } # Order service location /api/v1/orders { limit_req zone=order_svc burst=100 nodelay; proxy_pass http://order_service/orders; include /etc/nginx/includes/proxy.conf; include /etc/nginx/includes/tracing.conf; } # Product service location /api/v1/products { proxy_pass http://product_service/products; include /etc/nginx/includes/proxy.conf; include /etc/nginx/includes/tracing.conf; # Cache product listings proxy_cache product_cache; proxy_cache_valid 200 5m; proxy_cache_use_stale error timeout updating; add_header X-Cache-Status $upstream_cache_status; } # Payment service (critical) location /api/v1/payments { limit_req zone=payment_svc burst=5; limit_conn addr 3; proxy_pass http://payment_service/payments; include /etc/nginx/includes/proxy.conf; include /etc/nginx/includes/tracing.conf; # Longer timeout for payments proxy_read_timeout 60s; # No caching for payments proxy_no_cache 1; proxy_cache_bypass 1; }
}
Tổng kết
Trong bài này, bạn đã học:
- ✅ Microservices architecture patterns
- ✅ API Gateway implementation
- ✅ Service discovery (static, DNS, Consul)
- ✅ Circuit breaker patterns
- ✅ Retry policies với exponential backoff
- ✅ Per-service rate limiting
- ✅ Distributed tracing (OpenTelemetry, Jaeger, Zipkin)
- ✅ Service mesh integration (Istio, Consul Connect, Linkerd)
- ✅ Canary deployments
- ✅ Blue-green deployments
Key takeaways:
- API Gateway là central point for routing
- Service discovery enables dynamic scaling
- Circuit breakers prevent cascading failures
- Distributed tracing essential for debugging
- Rate limiting protects services
- Service mesh adds observability và resilience
- Canary và blue-green enable safe deployments
Microservices Checklist:
- ✅ API Gateway configured
- ✅ Service discovery implemented
- ✅ Health checks on all services
- ✅ Circuit breakers configured
- ✅ Retry policies defined
- ✅ Rate limiting per service
- ✅ Distributed tracing enabled
- ✅ Monitoring và alerting
- ✅ Deployment strategies tested
- ✅ Documentation complete
Với 14 bài học comprehensive này, bạn đã có đầy đủ kiến thức để deploy và manage Nginx trong production environments từ basic đến advanced, bao gồm microservices architectures! 🎉