翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。
サーキットブレーカーパターン
Intent
サーキットブレーカーパターンは、呼び出しが以前に繰り返しタイムアウトまたは失敗の原因となっていた場合に、発信者サービスが別のサービス (発信者 ) への呼び出しを再試行するのを防ぐことができます。このパターンは、発信者サービスがいつ再び機能するかを検出するのにも使用されます。
導入する理由
複数のマイクロサービスが協力してリクエストを処理すると、1 つ以上のサービスが利用できなくなったり、レイテンシーが長くなる可能性があります。複雑なアプリケーションがマイクロサービスを使用する場合、1 つのマイクロサービスが停止すると、アプリケーションの障害が発生する可能性があります。マイクロサービスはリモートプロシージャ呼び出しを介して通信し、ネットワーク接続で一時的なエラーが発生し、障害が発生する可能性があります。(一時的なエラーは、バックオフパターンで再試行することで処理できます)。同期実行中にタイムアウトや障害がカスケードされると、ユーザーエクスペリエンスが低下する可能性があります。
ただし、状況によっては、障害の解決に時間がかかる場合があります。例えば、受信者サービスがダウンしている場合や、データベースの競合によりタイムアウトが発生する場合などです。このような場合、呼び出し元のサービスが呼び出しを繰り返し再試行すると、これらの再試行によってネットワーク競合が発生し、データベーススレッドプールが消費される可能性があります。さらに、複数のユーザーがアプリケーションを繰り返し再試行すると、問題が悪化し、アプリケーション全体でパフォーマンスが低下する可能性があります。
サーキットブレーカーパターンは、マイケル・ナイガードが著書「Release It」(Nygard 2018) で人気がありました。この設計パターンにより、以前にタイムアウトや障害が繰り返し発生したサービス呼び出しを呼び出し元サービスが再試行するのを防ぐことができます。また、発信者サービスがいつ再び機能するかを検出することもできます。
サーキットブレーカーオブジェクトは、回路に異常があると自動的に現在の を中断するサーキットブレーカーのように機能します。サーキットブレーカーは、障害発生時に現在のフローを遮断または作動させます。同様に、サーキットブレーカーオブジェクトは発信者と発信者サービスの間にあり、発信者が利用できない場合は が作動します。
分散コンピューティングの誤
ネットワーク停止中、アプリケーションは応答を無期限に待機し、アプリケーションリソースを継続的に消費する可能性があります。ネットワークが使用可能になったときにオペレーションを再試行しないと、アプリケーションのパフォーマンスが低下する可能性があります。ネットワークの問題によりデータベースまたは外部サービスへのAPI呼び出しがタイムアウトした場合、サーキットブレーカーなしで繰り返し呼び出すと、コストとパフォーマンスに影響する可能性があります。
適用対象
このパターンは次の場合に使用します。
-
発信者サービスは、失敗する可能性が最も高い通話を行います。
-
発信者サービスによって発生するレイテンシーが高い場合 (データベース接続が遅い場合など)、発信者サービスにタイムアウトが発生します。
-
発信者サービスは同期呼び出しを行いますが、発信者サービスは利用できないか、レイテンシーが高くなります。
問題点と考慮事項
-
サービスに依存しない実装: コードの肥大化を防ぐため、マイクロサービスに依存しない API駆動型の方法でサーキットブレーカーオブジェクトを実装することをお勧めします。
-
発信者による回路閉鎖: 発信者がパフォーマンスの問題または障害から回復すると、回路ステータスを に更新できます
CLOSED
。これはサーキットブレーカーパターンの延長であり、目標復旧時間 (RTO) で必要な場合に実装できます。 -
マルチスレッド呼び出し: 有効期限タイムアウト値は、サービスの可用性を確認するために呼び出しが再度ルーティングされるまでに回路がトリップされたままである期間として定義されます。複数のスレッドで呼び出し先サービスが呼び出されると、最初に失敗した呼び出しによって有効期限のタイムアウト値が定義されます。実装では、後続の呼び出しで有効期限タイムアウトが無限に移動しないようにする必要があります。
-
回路を強制的に開閉する: システム管理者は回路を開閉できる必要があります。これは、データベーステーブルの有効期限タイムアウト値を更新することで実行できます。
-
オブザーバビリティ: アプリケーションには、サーキットブレーカーが開いているときに失敗する呼び出しを識別するためのログ記録が設定されている必要があります。
実装
高レベルのアーキテクチャ
次の例では、発信者が注文サービスで、発信者が支払いサービスです。
次の図に示すように、障害がない場合、注文サービスはサーキットブレーカーによってすべての呼び出しを支払いサービスにルーティングします。
支払いサービスがタイムアウトすると、サーキットブレーカーはタイムアウトを検出し、障害を追跡できます。
タイムアウトが指定されたしきい値を超えると、アプリケーションは回路を開きます。回路が開いている場合、サーキットブレーカーオブジェクトは呼び出しを支払いサービスにルーティングしません。注文サービスが支払いサービスを呼び出すと、すぐに失敗が返されます。
サーキットブレーカーオブジェクトは、支払いサービスの呼び出しが成功したかどうかを定期的に確認しようとします。
支払いサービスの呼び出しが成功すると、回路は閉じられ、それ以降のすべての呼び出しは支払いサービスに再度ルーティングされます。
AWS サービスを使用した実装
このサンプルソリューションでは、 でエクスプレスワークフローAWS Step Functions
このソリューションでは、Amazon DynamoDB
サービスが別のサービスを呼び出す場合、呼び出し元サービスの名前でワークフローを開始します。ワークフローは、現在低下しているサービスを保存する DynamoDB CircuitStatus
テーブルからサーキットブレーカーのステータスを取得します。に発信者の期限切れレコードCircuitStatus
が含まれている場合、回路は開いています。Step Functions ワークフローは即時障害を返し、 FAIL
状態で終了します。
CircuitStatus
テーブルに発信者のレコードが含まれていない場合、または期限切れのレコードが含まれている場合、サービスは動作します。ステートマシン定義の ExecuteLambda
ステップは、パラメータ値を介して送信される Lambda 関数を呼び出します。呼び出しが成功すると、Step Functions ワークフローは SUCCESS
状態で終了します。
サービス呼び出しが失敗するか、タイムアウトが発生すると、アプリケーションは定義された回数だけエクスポネンシャルバックオフで再試行します。再試行後にサービス呼び出しが失敗した場合、ワークフローは を使用してサービスのCircuitStatus
テーブルにレコードを挿入しExpiryTimeStamp
、ワークフローは FAIL
状態で終了します。同じサービスへの後続の呼び出しは、サーキットブレーカーが開いている限り、即時の障害を返します。ステートマシン定義の Get Circuit Status
ステップは、 ExpiryTimeStamp
値に基づいてサービスの可用性をチェックします。期限切れの項目は、DynamoDB 有効期限 (TTL) 機能を使用してCircuitStatus
テーブルから削除されます。
「サンプルコード」
次のコードでは、GetCircuitStatus
Lambda 関数を使用してサーキットブレーカーのステータスを確認します。
var serviceDetails = _dbContext.QueryAsync<CircuitBreaker>(serviceName, QueryOperator.GreaterThan, new List<object> {currentTimeStamp}).GetRemainingAsync(); if (serviceDetails.Result.Count > 0) { functionData.CircuitStatus = serviceDetails.Result[0].CircuitStatus; } else { functionData.CircuitStatus = ""; }
次のコードは、Step Functions ワークフローの Amazon States Language ステートメントを示しています。
"Is Circuit Closed": { "Type": "Choice", "Choices": [ { "Variable": "$.CircuitStatus", "StringEquals": "OPEN", "Next": "Circuit Open" }, { "Variable": "$.CircuitStatus", "StringEquals": "", "Next": "Execute Lambda" } ] }, "Circuit Open": { "Type": "Fail" }
GitHub リポジトリ
このパターンのサンプルアーキテクチャの完全な実装については、「」の「 GitHub リポジトリ」を参照してくださいhttps://github.com/aws-samples/circuit-breaker-netcore-blog