信頼性パターン

分散システムの障害に対処するためのパターン

分散システムでは障害は避けられない。 これらのパターンは障害を検知・隔離・回復するための仕組み。

Circuit Breaker(サーキットブレーカー)

障害が発生しているサービスへの呼び出しを遮断し、 システム全体への影響を防ぐ。電気のブレーカーと同じ発想。

状態遷移図

🟢
Closed
通常動作
リクエストを通す
閾値超過
5回失敗など
🔴
Open
遮断中
即座にエラー返却
タイムアウト後
30秒後など
🟡
Half-Open
試行中
一部リクエストで確認
成功 → Closedへ
失敗 → Openへ

典型的な設定値

Failure Threshold
5回失敗でOpen
Reset Timeout
30秒後にHalf-Open
Success Threshold
3回成功でClosed

Retry(リトライ)

一時的な障害に対して再試行する。 ただし、指数バックオフを使わないと障害を悪化させる。

Exponential Backoff(指数バックオフ)

1回目
1秒
2回目
2秒
3回目
4秒
4回目
8秒
5回目
16秒(最大値でキャップ)
+ Jitter(ランダム)

全クライアントが同時にリトライすると「Thundering Herd」問題。 待機時間に±20%程度のランダムを加える。

リトライすべき

  • • 503 Service Unavailable
  • • 429 Too Many Requests
  • • Connection timeout
  • • Network unreachable

リトライすべきでない

  • • 400 Bad Request
  • • 401 Unauthorized
  • • 404 Not Found
  • • 非冪等な操作(注意が必要)

Timeout(タイムアウト)

応答がない場合に待機を打ち切る。 タイムアウトがないと、リソースが無限に待機し続ける。

タイムアウトの階層

Connect Timeout
接続確立まで(通常: 1-5秒)
Read Timeout
レスポンス受信まで(通常: 5-30秒)
Request Timeout
リクエスト全体(通常: 30-60秒)

タイムアウトバジェット

Client
30秒
API Gateway
25秒
Service A
20秒
Service B
15秒
ポイント: 下流のタイムアウトは上流より短くする。 上流でタイムアウトしても下流が動き続けるのは無駄。

Bulkhead(隔壁)

リソースを分離して、一部の障害が全体に波及するのを防ぐ。 船の隔壁(浸水しても他の区画は守る)と同じ発想。

隔壁なし

共有スレッドプール (100)
Service A
20使用
Service B
80使用!
Service C
0 待機
Service Bの遅延でプール枯渇 → 全体に影響

隔壁あり

Pool A (30)
Service A
20使用
Pool B (30)
Service B
30使用!
Pool C (40)
Service C
正常動作
Service Bの問題は他に影響しない

Rate Limiting(レート制限)

リクエストの流量を制限して、システムを過負荷から守る。

主なアルゴリズム

Token Bucket

🪣
• 一定レートでトークン追加
• リクエストでトークン消費
• バーストを許容

Leaky Bucket

🚿
• 一定レートで処理
• 超過はキューに蓄積
• 安定した流量

パターンの組み合わせ

Client Request
Rate Limiter
過負荷防止
Bulkhead
リソース分離
Circuit Breaker
障害検知・遮断
Retry + Timeout
一時障害対応
Downstream Service

主な実装ライブラリ

Resilience4j

Java向け。Circuit Breaker, Retry, Rate Limiter, Bulkhead, Time Limiterを提供。

Polly

.NET向け。同様のパターンをfluent APIで提供。

Hystrix(非推奨)

Netflix製。メンテナンスモード。Resilience4jへの移行推奨。

Service Mesh

Istio/Linkerdでインフラレベルで実装。アプリ変更不要。