フォールトトレランスのためのサーキットブレーカーパターンを探求し、アプリケーションの回復力と安定性を向上させます。その実装、利点、多様な業界やグローバルな文脈での実例を学びましょう。
サーキットブレーカー:最新アプリケーションのための堅牢なフォールトトレランスパターン
ソフトウェア開発の領域、特にマイクロサービスアーキテクチャや分散システムにおいて、アプリケーションの回復力を確保することは最も重要です。コンポーネントが故障した場合、連鎖的な障害を防ぎ、安定的で応答性の高いユーザーエクスペリエンスを維持することが不可欠です。サーキットブレーカーパターンは、このようなシナリオでフォールトトレランスと優雅な劣化(グレースフルデグラデーション)を達成するための強力なソリューションとして登場します。
サーキットブレーカーパターンとは?
サーキットブレーカーパターンは、過電流による損傷から回路を保護する電気の回路ブレーカーから着想を得ています。ソフトウェアでは、失敗する可能性のある操作のプロキシとして機能し、アプリケーションが失敗する可能性の高い操作を繰り返し実行しようとするのを防ぎます。この積極的なアプローチにより、リソースの浪費を避け、レイテンシを削減し、最終的にシステムの安定性を向上させます。
中心的な考え方は、サービスが一貫して応答に失敗すると、サーキットブレーカーが「オープン」になり、そのサービスへのさらなるリクエストを防ぐというものです。定義された期間の後、サーキットブレーカーは「ハーフオープン」状態に入り、限られた数のテストリクエストを通過させます。これらのリクエストが成功すると、サーキットブレーカーは「クローズ」し、通常の操作を再開します。失敗した場合、サーキットブレーカーはオープンのままで、このサイクルが繰り返されます。
サーキットブレーカーの状態
サーキットブレーカーは3つの異なる状態で動作します:
- クローズ(Closed): これは通常の動作状態です。リクエストはサービスに直接ルーティングされます。サーキットブレーカーはこれらのリクエストの成功率と失敗率を監視します。失敗率が事前に定義されたしきい値を超えると、サーキットブレーカーはオープン状態に移行します。
- オープン(Open): この状態では、サーキットブレーカーはすべてのリクエストをショートサーキットさせ、即座にエラーまたはフォールバック応答を返します。これにより、アプリケーションが故障中のサービスをリトライで圧倒するのを防ぎ、サービスが回復する時間を与えます。
- ハーフオープン(Half-Open): オープン状態で指定されたタイムアウト期間が経過すると、サーキットブレーカーはハーフオープン状態に移行します。この状態では、限られた数のテストリクエストをサービスに通過させます。これらのリクエストが成功した場合、サーキットブレーカーはクローズ状態に戻ります。テストリクエストのいずれかが失敗した場合、サーキットブレーカーはオープン状態に戻ります。
サーキットブレーカーパターンを使用する利点
サーキットブレーカーパターンを実装することには、いくつかの重要な利点があります:
- 回復力の向上: 故障中のサービスへのリクエストを防ぐことで、連鎖的な障害を防ぎ、アプリケーションの可用性を維持します。
- 安定性の強化: 故障中のサービスへのリトライによってアプリケーションが圧倒されるのを防ぎ、リソースを節約し、全体的な安定性を向上させます。
- レイテンシの削減: 故障中のサービスからの応答を待つことによる不必要な遅延を避け、ユーザーへの応答時間を短縮します。
- 優雅な劣化(グレースフルデグラデーション): サービスが利用できない場合にアプリケーションの機能を優雅に劣化させ、単に失敗するよりも受け入れやすいユーザーエクスペリエンスを提供します。
- 自動回復: 故障中のサービスが再び利用可能になったときに自動的に回復し、ダウンタイムを最小限に抑えます。
- 障害の分離: システム内の障害を分離し、他のコンポーネントへの波及を防ぎます。
実装に関する考慮事項
サーキットブレーカーパターンを効果的に実装するには、いくつかの要素を慎重に考慮する必要があります:
- 失敗のしきい値: サーキットブレーカーをオープンするタイミングを決定するためのしきい値。これは特定のサービスとアプリケーションの要件に基づいて慎重に調整する必要があります。低いしきい値は早すぎるトリップにつながる可能性があり、高いしきい値は十分な保護を提供しない可能性があります。
- タイムアウト期間: サーキットブレーカーがオープン状態からハーフオープン状態に移行するまでの時間。この期間は、故障中のサービスが回復するのに十分な長さであるべきですが、ダウンタイムを最小限に抑えるために十分に短い必要があります。
- ハーフオープン状態のテストリクエスト: ハーフオープン状態で許可されるテストリクエストの数。この数は、回復中のサービスを圧倒するリスクを最小限に抑えるのに十分小さく、その健全性に関する信頼できる指標を提供するのに十分な大きさである必要があります。
- フォールバックメカニズム: サーキットブレーカーがオープンしているときにフォールバック応答や機能を提供するためのメカニズム。これには、キャッシュされたデータを返す、ユーザーフレンドリーなエラーメッセージを表示する、またはユーザーを代替サービスにリダイレクトするなどが含まれます。
- 監視とロギング: サーキットブレーカーの状態、失敗の数、リクエストの成功率を追跡するための包括的な監視とロギング。この情報は、システムの動作を理解し、問題を診断・解決するために不可欠です。
- 設定: 失敗のしきい値、タイムアウト期間、ハーフオープン状態のテストリクエストなどの設定パラメータを外部化し、コードの変更を必要とせずに動的な調整を可能にします。
実装例
サーキットブレーカーパターンは、様々なプログラミング言語やフレームワークを使用して実装できます。以下にいくつかの例を挙げます:
JavaとResilience4j
Resilience4jは、サーキットブレーカー、リトライ、レートリミッター、バルクヘッドなど、包括的なフォールトトレランスツールスイートを提供する人気のJavaライブラリです。以下は基本的な例です:
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofMillis(1000))
.permittedNumberOfCallsInHalfOpenState(2)
.slidingWindowSize(10)
.build();
CircuitBreaker circuitBreaker = CircuitBreaker.of("myService", circuitBreakerConfig);
Supplier<String> decoratedSupplier = CircuitBreaker
.decorateSupplier(circuitBreaker, () -> myRemoteService.getData());
try {
String result = decoratedSupplier.get();
// 結果を処理
} catch (RequestNotPermitted e) {
// オープンサーキットを処理
System.err.println("Circuit is open: " + e.getMessage());
}
PythonとPybreaker
Pybreakerは、シンプルで使いやすいサーキットブレーカーの実装を提供するPythonライブラリです。
import pybreaker
breaker = pybreaker.CircuitBreaker(fail_max=3, reset_timeout=10)
@breaker
def unreliable_function():
# ここに信頼性の低い関数呼び出しを記述
pass
try:
unreliable_function()
except pybreaker.CircuitBreakerError:
print("Circuit Breaker is open!")
.NETとPolly
Pollyは、開発者がリトライ、サーキットブレーカー、タイムアウト、バルクヘッドなどのポリシーを流暢かつ構成可能な方法で表現できる、.NETの回復力および一時的な障害処理ライブラリです。
var circuitBreakerPolicy = Policy
.Handle<Exception>()
.CircuitBreakerAsync(
exceptionsAllowedBeforeBreaking: 3,
durationOfBreak: TimeSpan.FromSeconds(10),
onBreak: (exception, timespan) =>
{
Console.WriteLine("Circuit Breaker opened: " + exception.Message);
},
onReset: () =>
{
Console.WriteLine("Circuit Breaker reset.");
},
onHalfOpen: () =>
{
Console.WriteLine("Circuit Breaker half-opened.");
});
try
{
await circuitBreakerPolicy.ExecuteAsync(async () =>
{
// ここに信頼性の低い操作を記述
await MyRemoteService.GetDataAsync();
});
}
catch (Exception ex)
{
Console.WriteLine("Handled exception: " + ex.Message);
}
実世界での例
サーキットブレーカーパターンは、様々な業界やアプリケーションで広く使用されています:
- Eコマース: 決済ゲートウェイが利用できない場合の連鎖的な障害を防ぎ、ショッピングカートとチェックアウトプロセスが機能し続けることを保証します。例:グローバルなEコマースプラットフォームで特定の決済プロバイダーが特定の地域(例:東南アジア)でダウンした場合、サーキットブレーカーが開き、トランザクションはその地域の代替プロバイダーにルーティングされるか、システムがユーザーに代替の支払い方法を提供できます。
- 金融サービス: 取引システム内の障害を分離し、不正確または不完全なトランザクションを防ぎます。例:取引のピーク時に、証券会社の注文執行サービスが断続的な障害を経験する可能性があります。サーキットブレーカーは、そのサービスを介して注文を繰り返し試みることを防ぎ、システムを過負荷や潜在的な金銭的損失から保護します。
- クラウドコンピューティング: クラウドサービスの一時的な停止に対処し、アプリケーションが利用可能で応答性を維持することを保証します。例:グローバルなマーケティングプラットフォームで使用されるクラウドベースの画像処理サービスが特定のデータセンターで利用できなくなった場合、サーキットブレーカーが開き、リクエストを別のデータセンターにルーティングするか、フォールバックサービスを利用して、プラットフォームユーザーへの影響を最小限に抑えます。
- IoT: IoTデバイスとの接続性の問題を管理し、システムが故障したデバイスによって圧倒されるのを防ぎます。例:異なる地理的な場所に多数の接続デバイスを持つスマートホームシステムで、特定の地域(例:ヨーロッパ)の特定のタイプのセンサーが誤ったデータを報告し始めたり、応答しなくなったりした場合、サーキットブレーカーはそれらのセンサーを分離し、システム全体のパフォーマンスに影響を与えるのを防ぐことができます。
- ソーシャルメディア: サードパーティAPI統合の一時的な障害に対処し、ソーシャルメディアプラットフォームが機能し続けることを保証します。例:ソーシャルメディアプラットフォームが外部コンテンツを表示するためにサードパーティAPIに依存しており、そのAPIがダウンした場合、サーキットブレーカーはAPIへの繰り返しのリクエストを防ぎ、キャッシュされたデータまたはデフォルトのメッセージをユーザーに表示して、障害の影響を最小限に抑えます。
サーキットブレーカー vs. リトライパターン
サーキットブレーカーとリトライパターンはどちらもフォールトトレランスのために使用されますが、異なる目的を果たします。
- リトライパターン: 失敗した操作を自動的に再試行します。障害が一時的なものであり、後続の試行で成功する可能性があると想定します。断続的なネットワークの不具合や一時的なリソースの枯渇に役立ちます。基盤となるサービスが本当にダウンしている場合、問題を悪化させる可能性があります。
- サーキットブレーカーパターン: 失敗している操作の繰り返し実行を防ぎます。障害が持続的であると想定します。連鎖的な障害を防ぎ、故障中のサービスに回復の時間を与えるのに役立ちます。
場合によっては、これらのパターンを一緒に使用することもできます。例えば、サーキットブレーカー内にリトライパターンを実装することがあります。サービスが一貫して失敗している場合、サーキットブレーカーは過剰なリトライを防ぎ、リトライパターンはサーキットブレーカーがトリガーされる前に一時的なエラーを処理します。
避けるべきアンチパターン
サーキットブレーカーは強力なツールですが、潜在的なアンチパターンに注意することが重要です:
- 不適切な設定: 失敗のしきい値やタイムアウト期間を高く設定しすぎたり、低く設定しすぎたりすると、早すぎるトリップや不十分な保護につながる可能性があります。
- 監視の欠如: サーキットブレーカーの状態を監視しないと、根本的な問題を特定して解決することができなくなります。
- フォールバックの無視: フォールバックメカニズムを提供しないと、サーキットブレーカーが開いているときにユーザーエクスペリエンスが低下する可能性があります。
- 過度の依存: サービスにおける基本的な信頼性の問題に対処する代わりとしてサーキットブレーカーを使用すること。サーキットブレーカーは安全策であり、解決策ではありません。
- 下流の依存関係を考慮しないこと: サーキットブレーカーは直近の呼び出し元を保護します。障害の伝播を防ぐために、下流のサービスにも適切なサーキットブレーカーがあることを確認してください。
高度な概念
- 適応型しきい値: 過去のパフォーマンスデータに基づいて失敗のしきい値を動的に調整します。
- ローリングウィンドウ: ローリングウィンドウを使用して失敗率を計算し、最近のパフォーマンスをより正確に表現します。
- コンテキストに応じたサーキットブレーカー: リクエストのタイプやユーザーごとに異なるサーキットブレーカーを作成し、よりきめ細かい制御を可能にします。
- 分散サーキットブレーカー: 分散システムの複数のノードにわたってサーキットブレーカーを実装し、障害が分離・封じ込められることを保証します。