Circuit Breaker
Circuit Breaker は、障害が発生しているサービスを自動的に隔離し、カスケード障害を防止します。
目次
- Circuit Breaker が必要な理由
- Circuit Breaker の概要
- 接続プールの設定
- Outlier Detection
- Retry ポリシーとの組み合わせ
- 実践例
- 外部サービスの Circuit Breaker
- モニタリングとデバッグ
- 重要な考慮事項
- ベストプラクティス
Circuit Breaker が必要な理由
カスケード障害の防止
マイクロサービスアーキテクチャでは、あるサービスの障害が他のサービスへ波及することを防ぎます。
主な利点
| 問題 | Circuit Breaker なし | Circuit Breaker あり |
|---|---|---|
| 応答時間 | タイムアウトまで待機(30 秒以上) | 即時失敗(1ms) |
| リソース使用量 | スレッド/接続の枯渇 | リソースを保護 |
| 障害の伝播 | カスケード障害が発生 | 障害を隔離 |
| 復旧時間 | 手動介入が必要 | 自動復旧を試行 |
Circuit Breaker の概要
接続プールの設定
yaml
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: reviews-circuit-breaker
spec:
host: reviews
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
http1MaxPendingRequests: 50
http2MaxRequests: 100
maxRequestsPerConnection: 2Outlier Detection
Outlier Detection は、正常でないインスタンスを自動的に除外します。
yaml
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: reviews-outlier
spec:
host: reviews
trafficPolicy:
outlierDetection:
consecutiveErrors: 5 # 5 consecutive errors
interval: 30s # Check every 30 seconds
baseEjectionTime: 30s # Remove for 30 seconds
maxEjectionPercent: 50 # Remove up to 50%
minHealthPercent: 40 # Maintain at least 40%高度な Outlier Detection の設定
yaml
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: advanced-outlier
spec:
host: api-service
trafficPolicy:
outlierDetection:
# Consecutive error based
consecutiveGatewayErrors: 5 # 5xx errors 5 times
consecutive5xxErrors: 3 # 500~599 errors 3 times
# Time intervals
interval: 10s # Check every 10 seconds
baseEjectionTime: 30s # First ejection time
maxEjectionTime: 300s # Maximum ejection time
# Rate limits
maxEjectionPercent: 50 # Remove up to 50%
minHealthPercent: 30 # Maintain at least 30%
# Success rate based
splitExternalLocalOriginErrors: trueRetry ポリシーとの組み合わせ
耐障害性を高めるために、Circuit Breaker を Retry とともに使用します。
基本的な組み合わせ
yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: reviews-retry
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
retries:
attempts: 3 # 3 retries
perTryTimeout: 2s # 2 second timeout per attempt
retryOn: 5xx,reset,connect-failure
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: reviews-circuit-breaker
spec:
host: reviews
trafficPolicy:
connectionPool:
http:
http1MaxPendingRequests: 10
maxRequestsPerConnection: 2
outlierDetection:
consecutiveErrors: 5
interval: 10s
baseEjectionTime: 30sRetry Budget パターン
yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: payment-retry-budget
spec:
hosts:
- payment-service
http:
- route:
- destination:
host: payment-service
retries:
attempts: 2 # Minimize retries
perTryTimeout: 1s # Fast fail
retryOn: retriable-4xx,5xx
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: payment-circuit-breaker
spec:
host: payment-service
trafficPolicy:
connectionPool:
http:
http1MaxPendingRequests: 5 # Low queue
maxRequestsPerConnection: 1 # 1 request per connection
outlierDetection:
consecutiveErrors: 3 # Fast blocking
interval: 5s
baseEjectionTime: 60s # Long recovery time実践例
1. メッシュ内サービス向け Circuit Breaker
シナリオ: データベースサービスの保護
yaml
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: database-service-circuit-breaker
namespace: production
spec:
host: database-service
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100 # Maximum 100 connections
http:
http1MaxPendingRequests: 50 # 50 pending requests
http2MaxRequests: 100 # HTTP/2 100 concurrent requests
maxRequestsPerConnection: 2 # Maximum 2 requests per connection
idleTimeout: 60s # Idle connection timeout
outlierDetection:
consecutiveErrors: 5
interval: 30s
baseEjectionTime: 30s
maxEjectionPercent: 50
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2ユースケース:
- データベース接続プールの枯渇を防止する
- 遅いクエリによるカスケード障害をブロックする
- 正常でないインスタンスを自動的に除外する
2. maxConnections: 1 パターン(単一接続)
シナリオ: レガシーシステムまたはリソース制約のあるサービス
yaml
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: legacy-system-protection
spec:
host: legacy-api-service
trafficPolicy:
connectionPool:
tcp:
maxConnections: 1 # Limit to 1 connection
http:
http1MaxPendingRequests: 1 # 1 pending request
maxRequestsPerConnection: 1 # 1 request per connection
h2UpgradePolicy: DO_NOT_UPGRADE # Prevent HTTP/2 upgrade
outlierDetection:
consecutiveErrors: 1 # Block immediately on 1 error
interval: 10s
baseEjectionTime: 60sユースケース:
- レガシーシステムが同時接続を処理できない場合
- 外部 API のレート制限が非常に厳しい場合
- 単一接続による順次処理が必要な場合
3. サブセットごとの Circuit Breaker
シナリオ: バージョンごとに異なる Circuit Breaker 設定
yaml
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: reviews-subset-circuit-breaker
spec:
host: reviews
trafficPolicy:
# Default policy (all subsets)
connectionPool:
http:
http1MaxPendingRequests: 50
maxRequestsPerConnection: 2
outlierDetection:
consecutiveErrors: 5
interval: 30s
baseEjectionTime: 30s
subsets:
- name: v1
labels:
version: v1
# v1 uses default policy
- name: v2
labels:
version: v2
trafficPolicy:
# v2 has stricter policy (new version testing)
connectionPool:
http:
http1MaxPendingRequests: 10
maxRequestsPerConnection: 1
outlierDetection:
consecutiveErrors: 3
interval: 10s
baseEjectionTime: 60s
- name: v3-canary
labels:
version: v3
trafficPolicy:
# v3 Canary is very strict (initial deployment)
connectionPool:
http:
http1MaxPendingRequests: 5
maxRequestsPerConnection: 1
outlierDetection:
consecutiveErrors: 1
interval: 5s
baseEjectionTime: 120s4. 高度な接続プールパターン
シナリオ: 高性能サービス
yaml
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: high-performance-service
spec:
host: api-gateway
trafficPolicy:
connectionPool:
tcp:
maxConnections: 1000 # High concurrent connections
connectTimeout: 3s
tcpKeepalive:
time: 7200s
interval: 75s
probes: 9
http:
http1MaxPendingRequests: 500
http2MaxRequests: 1000
maxRequestsPerConnection: 100 # Connection reuse
idleTimeout: 300s
h2UpgradePolicy: UPGRADE # Use HTTP/2
outlierDetection:
consecutiveErrors: 10 # Lenient setting
interval: 60s
baseEjectionTime: 30s
maxEjectionPercent: 20 # Remove up to 20% only5. ヘルスチェックに基づく Circuit Breaker
yaml
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: health-check-circuit-breaker
spec:
host: payment-service
trafficPolicy:
outlierDetection:
# HTTP status code based
consecutiveGatewayErrors: 5 # 502, 503, 504
consecutive5xxErrors: 3 # 500~599
# Performance based
interval: 10s
baseEjectionTime: 30s
maxEjectionTime: 300s # Maximum 5 minutes
# Dynamic adjustment
splitExternalLocalOriginErrors: true
consecutiveLocalOriginFailures: 5外部サービスの Circuit Breaker
ServiceEntry とともに使用して、外部サービスを保護します。
1. 外部 API の Circuit Breaker
yaml
# ServiceEntry: Register external API
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: external-payment-api
spec:
hosts:
- api.payment-provider.com
ports:
- number: 443
name: https
protocol: HTTPS
location: MESH_EXTERNAL
resolution: DNS
---
# DestinationRule: Apply Circuit Breaker
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: external-payment-api-circuit-breaker
spec:
host: api.payment-provider.com
trafficPolicy:
connectionPool:
tcp:
maxConnections: 10 # External API is limited
http:
http1MaxPendingRequests: 5
maxRequestsPerConnection: 1 # Minimize connection reuse
outlierDetection:
consecutiveErrors: 3 # Fast blocking
interval: 30s
baseEjectionTime: 120s # Long recovery time
maxEjectionPercent: 100 # Can completely block
tls:
mode: SIMPLE # TLS connection2. 外部データベースの Circuit Breaker
yaml
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: external-mongodb
spec:
hosts:
- mongodb.external-cluster.com
ports:
- number: 27017
name: tcp
protocol: TCP
location: MESH_EXTERNAL
resolution: DNS
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: external-mongodb-circuit-breaker
spec:
host: mongodb.external-cluster.com
trafficPolicy:
connectionPool:
tcp:
maxConnections: 50
connectTimeout: 5s
outlierDetection:
consecutiveErrors: 5
interval: 60s
baseEjectionTime: 60s3. レート制限のある外部サービス
yaml
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: rate-limited-api
spec:
hosts:
- api.rate-limited-service.com
ports:
- number: 443
name: https
protocol: HTTPS
location: MESH_EXTERNAL
resolution: DNS
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: rate-limited-api-protection
spec:
host: api.rate-limited-service.com
trafficPolicy:
connectionPool:
http:
http1MaxPendingRequests: 1 # Minimize queue
maxRequestsPerConnection: 1 # Prevent rate limit exceeding
idleTimeout: 1s # Fast connection release
outlierDetection:
consecutiveErrors: 1 # Block immediately on 429 error
interval: 60s
baseEjectionTime: 300s # Wait 5 minutes (rate limit reset)
---
# VirtualService: Retry settings
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: rate-limited-api-retry
spec:
hosts:
- api.rate-limited-service.com
http:
- route:
- destination:
host: api.rate-limited-service.com
retries:
attempts: 0 # Disable retry (rate limit)
timeout: 10sモニタリングとデバッグ
Envoy メトリクスを確認する
bash
# Check Circuit Breaker status
kubectl exec -it <pod-name> -c istio-proxy -- \
curl localhost:15000/stats/prometheus | grep circuit_breakers
# Outlier Detection status
kubectl exec -it <pod-name> -c istio-proxy -- \
curl localhost:15000/stats/prometheus | grep outlier_detection
# Connection Pool status
kubectl exec -it <pod-name> -c istio-proxy -- \
curl localhost:15000/stats/prometheus | grep upstream_rq主なメトリクス
yaml
# Prometheus queries
# Circuit Breaker Open count
envoy_cluster_circuit_breakers_default_rq_open
# Pending request count
envoy_cluster_circuit_breakers_default_rq_pending_open
# Outlier Detection Ejection
envoy_cluster_outlier_detection_ejections_active
# Connection pool overflow
envoy_cluster_upstream_rq_pending_overflow
# Retry count
envoy_cluster_upstream_rq_retryGrafana ダッシュボード
yaml
# Circuit Breaker Dashboard
- expr: rate(envoy_cluster_circuit_breakers_default_rq_open[5m])
legend: "Circuit Breaker Open Rate"
- expr: envoy_cluster_outlier_detection_ejections_active
legend: "Ejected Instances"
- expr: rate(envoy_cluster_upstream_rq_pending_overflow[5m])
legend: "Connection Pool Overflow"istioctl コマンド
bash
# Check Proxy configuration
istioctl proxy-config cluster <pod-name> --fqdn reviews.default.svc.cluster.local
# Check Circuit Breaker settings
istioctl proxy-config cluster <pod-name> -o json | \
jq '.[] | select(.name=="outbound|9080||reviews.default.svc.cluster.local") | .circuitBreakers'
# Check Outlier Detection settings
istioctl proxy-config cluster <pod-name> -o json | \
jq '.[] | select(.name=="outbound|9080||reviews.default.svc.cluster.local") | .outlierDetection'重要な考慮事項
Circuit Breaker はデータ整合性を保証しない
基本原則: Circuit Breaker は、障害の隔離のためのツールであり、重複リクエストの防止やデータ整合性の保証のためのものではありません。
Circuit Breaker の役割と制限
問題シナリオ: Retry + Circuit Breaker
問題: Circuit Breaker が有効化される前(連続する 5 件のエラーの後)に、すでに3 件の重複した支払いが発生しています。
誤った使用例
yaml
# Dangerous: POST request + Retry + Circuit Breaker
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: payment-dangerous
spec:
hosts:
- payment-service
http:
- route:
- destination:
host: payment-service
retries:
attempts: 3 # 3 retries on POST
perTryTimeout: 2s
retryOn: 5xx,reset
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: payment-circuit-breaker
spec:
host: payment-service
trafficPolicy:
outlierDetection:
consecutiveErrors: 5
interval: 30s
baseEjectionTime: 30s
# Result:
# - Up to 15 duplicates possible before Circuit Breaker activates (3 retries x 5 errors)
# - Critical operations like payment, inventory deduction get duplicated
# - Data consistency destroyed正しい使用パターン
パターン 1: Circuit Breaker のみ(Retry を無効化)
yaml
# Safe: Read-only + Circuit Breaker
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: product-catalog-safe
spec:
hosts:
- product-catalog
http:
- match:
- method:
regex: "GET|HEAD|OPTIONS" # Read-only only
route:
- destination:
host: product-catalog
retries:
attempts: 3 # GET is safe
perTryTimeout: 2s
retryOn: 5xx,reset,connect-failure
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: product-catalog-circuit-breaker
spec:
host: product-catalog
trafficPolicy:
outlierDetection:
consecutiveErrors: 5
interval: 30s
baseEjectionTime: 30syaml
# Safe: Disable Retry for POST
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: payment-safe
spec:
hosts:
- payment-service
http:
- match:
- method:
exact: POST
route:
- destination:
host: payment-service
timeout: 10s
retries:
attempts: 0 # Disable Retry for POST
# Or
# attempts: 1
# retryOn: connect-failure,refused-stream # Network only
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: payment-circuit-breaker
spec:
host: payment-service
trafficPolicy:
outlierDetection:
consecutiveErrors: 5
interval: 30s
baseEjectionTime: 30sパターン 2: アプリケーションレベルの冪等性 + Circuit Breaker
python
# Server: Idempotency Key validation
@app.route('/payment', methods=['POST'])
def create_payment():
idempotency_key = request.headers.get('X-Idempotency-Key')
if not idempotency_key:
return jsonify({"error": "Missing Idempotency-Key"}), 400
# Check if request was already processed
if redis.exists(f"payment:idempotency:{idempotency_key}"):
cached_result = redis.get(f"payment:result:{idempotency_key}")
return jsonify(json.loads(cached_result)), 200
# Process new payment
try:
payment = process_payment(request.json)
# Cache result (24 hours)
redis.setex(f"payment:idempotency:{idempotency_key}", 86400, "1")
redis.setex(f"payment:result:{idempotency_key}", 86400,
json.dumps(payment))
return jsonify(payment), 201
except Exception as e:
return jsonify({"error": str(e)}), 500yaml
# Istio: Retry is safe when Idempotency is guaranteed
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: payment-with-idempotency
spec:
hosts:
- payment-service
http:
- match:
- headers:
x-idempotency-key:
regex: ".+" # Idempotency Key required
route:
- destination:
host: payment-service
retries:
attempts: 3 # Safe with Idempotency
perTryTimeout: 2s
retryOn: 5xx,reset
- route: # Disable Retry without Idempotency Key
- destination:
host: payment-service
retries:
attempts: 0サービス種別ごとの安全戦略
| サービス種別 | Retry | Circuit Breaker | 冪等性が必要 |
|---|---|---|---|
| 商品カタログ | 3 回 | 必須 | 不要 |
| ショッピングカート | 3 回 | 必須 | 不要 |
| 注文の作成 | 0 回 | 必須 | 必須 |
| 支払い | 0 回 | 必須 | 必須 |
| 在庫の差し引き | 0 回 | 必須 | 必須 |
| ポイントの加算 | 0 回 | 必須 | 必須 |
| 通知の送信 | 3 回(冪等) | 必須 | 推奨 |
接続プールとデータ整合性
接続プールの設定も、データ整合性を保証しません。同時接続数を制限するだけです。
yaml
# Misconception: Does maxConnections=1 prevent duplicates?
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: payment-single-connection
spec:
host: payment-service
trafficPolicy:
connectionPool:
tcp:
maxConnections: 1 # Does NOT prevent duplicates
http:
http1MaxPendingRequests: 1
# maxConnections=1:
# - Only limits concurrent connections
# - Cannot prevent duplicate requests from Retry
# - Retries after network timeout are separate connections実践チェックリスト
デプロイ前の確認:
- [ ] POST/PUT/DELETE/PATCH リクエストの Retry 設定を確認する
- [ ] 非冪等リクエストには
attempts: 0またはretryOn: connect-failureを設定する - [ ] Circuit Breaker と Retry を組み合わせる際は重複の可能性を確認する
- [ ] 重要な操作(支払い、在庫)には Idempotency Key を実装する
- [ ] アプリケーションレベルの検証ロジックが存在することを確認する
- [ ] テスト環境で障害シミュレーションを実施する
モニタリング:
bash
# Check Retry occurrence count
kubectl exec -n <namespace> <pod> -c istio-proxy -- \
curl -s localhost:15000/stats/prometheus | grep upstream_rq_retry
# Check Circuit Breaker activation
kubectl exec -n <namespace> <pod> -c istio-proxy -- \
curl -s localhost:15000/stats/prometheus | grep circuit_breakers
# Check logs for suspected duplicate requests
kubectl logs -n <namespace> <pod> | grep -i "duplicate\|idempotency"ベストプラクティス
1. 段階的な設定
yaml
# Stage 1: Start with lenient settings
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: service-circuit-breaker-stage1
spec:
host: my-service
trafficPolicy:
connectionPool:
http:
http1MaxPendingRequests: 100
maxRequestsPerConnection: 10
outlierDetection:
consecutiveErrors: 10 # Lenient
interval: 60s
baseEjectionTime: 30syaml
# Stage 2: Adjust after monitoring
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: service-circuit-breaker-stage2
spec:
host: my-service
trafficPolicy:
connectionPool:
http:
http1MaxPendingRequests: 50
maxRequestsPerConnection: 5
outlierDetection:
consecutiveErrors: 5 # Moderate
interval: 30s
baseEjectionTime: 30s2. サービス種別に固有の設定
yaml
# Frontend service: Lenient
connectionPool:
http:
http1MaxPendingRequests: 100
maxRequestsPerConnection: 10
outlierDetection:
consecutiveErrors: 10
# Backend service: Moderate
connectionPool:
http:
http1MaxPendingRequests: 50
maxRequestsPerConnection: 5
outlierDetection:
consecutiveErrors: 5
# Database/Cache: Strict
connectionPool:
http:
http1MaxPendingRequests: 10
maxRequestsPerConnection: 2
outlierDetection:
consecutiveErrors: 3
# External API: Very strict
connectionPool:
http:
http1MaxPendingRequests: 5
maxRequestsPerConnection: 1
outlierDetection:
consecutiveErrors: 13. アラート設定
yaml
# Prometheus Alert Rules
groups:
- name: circuit-breaker
rules:
- alert: CircuitBreakerOpen
expr: envoy_cluster_circuit_breakers_default_rq_open > 0
for: 1m
annotations:
summary: "Circuit breaker is open"
- alert: HighConnectionPoolOverflow
expr: rate(envoy_cluster_upstream_rq_pending_overflow[5m]) > 10
for: 2m
annotations:
summary: "Connection pool overflow rate is high"
- alert: HighOutlierEjectionRate
expr: rate(envoy_cluster_outlier_detection_ejections_total[5m]) > 5
for: 3m
annotations:
summary: "High outlier ejection rate"4. テストシナリオ
bash
#!/bin/bash
# Circuit Breaker test
# 1. Normal traffic
echo "=== Normal Traffic ==="
for i in {1..10}; do
curl -s http://service/api | jq .status
sleep 0.1
done
# 2. Increased load
echo "=== Increased Load ==="
for i in {1..100}; do
curl -s http://service/api &
done
wait
# 3. Check Circuit Breaker status
echo "=== Circuit Breaker Status ==="
istioctl proxy-config cluster <pod> | grep circuit_breakers
# 4. Wait for recovery
echo "=== Waiting for Recovery ==="
sleep 30
# 5. Verify recovery
echo "=== Recovery Check ==="
curl -s http://service/api | jq .status5. ドキュメントテンプレート
yaml
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: my-service-circuit-breaker
annotations:
# Configuration purpose
purpose: "Protect database connection pool"
# Threshold rationale
threshold-rationale: |
- maxConnections: 100 (DB connection pool size)
- consecutiveErrors: 5 (observed error pattern)
- baseEjectionTime: 30s (average recovery time)
# Test results
test-results: |
- Load test: 1000 RPS without overflow
- Failure test: Circuit opens after 5 errors
- Recovery test: Auto-recovery after 30s
# Operations guide
operations: |
- Monitor: envoy_cluster_circuit_breakers_*
- Alert: Circuit open > 1min
- Rollback: kubectl delete dr my-service-circuit-breaker