パターン:サーキットブレーカー
コンテキスト
マイクロサービスアーキテクチャを適用しました。サービスは、要求を処理するときに協力することがあります。あるサービスが別のサービスを同期的に呼び出す場合、他のサービスが利用できないか、またはそのような高いレイテンシを示す可能性が常にあります。スレッドなどの貴重なリソースは、他のサービスが応答するのを待っている間に呼び出し元で消費される可能性があります。これにより、リソースが枯渇し、呼び出し元のサービスが他の要求を処理できなくなる可能性があります。あるサービスの障害は、アプリケーション全体で他のサービスに連鎖する可能性があります。
問題
ネットワークまたはサービスの障害が他のサービスにカスケードするのを防ぐ方法は?
ソリューション
サービスクライアントは、電気回路ブレーカと同様の方法で機能するプロキシを介してリモートサービスを呼び出す必要があります。連続した障害の数がしきい値を超えると、サーキットブレーカがトリップし、タイムアウト期間の間、リモートサービスを呼び出すすべての試行はすぐに失敗タイムアウトの有効期限が切れた後、サーキットブレーカは、限られた数のテスト要求を通過させることができます。これらの要求が成功すると、サーキットブレーカは通常の動作を再開します。それ以外の場合は、障害が発生した場合、タイムアウト期間が再び開始されます。
サンプルアプリケーションの
RegistrationServiceProxy
は、Scalaで書かれたコンポーネントの例で、リモートサービスを呼び出すときに障害を処理するためにサーキットブレーカを使用し
@Componentclass RegistrationServiceProxy @Autowired()(restTemplate: RestTemplate) extends RegistrationService { @Value("${user_registration_url}") var userRegistrationUrl: String = _ @HystrixCommand(commandProperties=Array(new HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value="800"))) override def registerUser(emailAddress: String, password: String): Either = { try { val response = restTemplate.postForEntity(userRegistrationUrl, RegistrationBackendRequest(emailAddress, password), classOf) response.getStatusCode match { case HttpStatus.OK => Right(response.getBody.id) } } catch { case e: HttpClientErrorException if e.getStatusCode == HttpStatus.CONFLICT => Left(DuplicateRegistrationError) } }}
@HystrixCommand
は、遮断器を使用してregisterUser()
への呼び出しを実行するように配置します。
サーキットブレーカ機能は、UserRegistrationConfiguration
クラスの@EnableCircuitBreaker
アノテーションを使用して有効になります。
@EnableCircuitBreakerclass UserRegistrationConfiguration {
結果のコンテキスト
このパターンには次の利点があります:
- サービスが呼び出すサービスの障害を処理する
このパターンには次の問題があります:
- 誤検知を作成したり、過度のレイテンシを導入したりすることなく、タイムアウト値を選択することは困難です。
- マイクロサービスシャーシはこのパターンを実装する可能性があります
- APIゲートウェイはこのパターンを使用してサービスを呼び出す可能性があります
- サーバー側の検出ルーターはこのパターンを使用してサービスを呼び出す可能性があります
関連項目
- Netflix Hystrixは、このパターンを実装するライブラリの例です