Circuit Breaker Pattern (ShanonAdventCalendar2017 - 24日目)

このエントリーをはてなブックマークに追加
開発のou.gです。今日はCircuit Breaker Patternを簡単にご紹介します。

分散システム間の連携で、リモートサービスやリソースを接続するときに、接続対象が故障、高負荷等によって、応答が遅くなったり、ひいてはtimeoutになることがあります。そのまま呼び出しを続けると、内部のDDoSとなり、対象サービスの計算リソースの枯渇になってしまい、完全に死んでしまう可能性があります。

特に多数のサービスによって構成される複雑システムの場合に、一つのサービス故障がほかのサービスの連鎖故障を引き起こして、雪崩のように全サービス故障になってしまう可能性もあります。

このような問題を解決・緩和する方法はいくつがありますが、今回はCircuit Breaker Patternを紹介します。

Circuit Breaker Pattern(https://martinfowler.com/bliki/CircuitBreaker.html) を簡単にまとめると、呼び出す側に遮断器のような仕組みを用意して、依存サービスの異常を検知したら、自動的に遮断器を開いて、呼び出しを一時的に遮断します。そのあと、定期的サービスを呼び出して見て、成功したら遮断器を閉じてすべての呼び出しを開放することで自己回復します。

Circuit Breakerの内部は、有限状態機械をもって、下記の感じで状態遷移しています。

  • 閉(Closed):  正常状態、すべての呼び出しは正常通過します。一定期間内の失敗率が閾値を超えたら、Open状態に遷移。
  • 開(Open): 異常状態、すべての呼び出しを遮断して、すぐ失敗させてFallbackする。一定の時間後、Half Openに遷移。
  • 半開(Half Open): 呼び出しをやってみて、成功したらClosed状態に遷移、失敗したら、Open状態に戻り。

Circuit BreakerがOpen状態になったら、自分の業務に合わせて、適切なFallback処理をするべき、例えば、
  • 空白、Default値を返却、あるいは何もしない(fail-silent)
  • 例外処理に入って異常終了(fail-fast)
  • 非同期で後で再実行(retry)
  • 全遮断ではなく、半分遮断とか

Circuit Breaker使うとき、下記のことを考慮したほうが良いかもしれません。
  • 業務処理の冪等性: 呼び出し側がTimeoutになって失敗処理に入るが、サービス側に実際処理成功した可能性があります。この場合に、再実行しても問題にならないように処理の冪等性保障しないと泣きます。
  • 遮断対象の粒度: 依存サービスの故障、負荷問題がなくても、特定の処理が時間長くて、Timeoutになってすべての呼び出しが遮断されてしまうと困るから、業務に合わせてCircuit Breakerの遮断対象の粒度を制御しましょう。
  • 通知: 遮断処理動作するときに、担当者に通知したほうが良い。頻繁に起きたら、依存サービスは問題ないか、根本的に処理能力を上げた方が良いかを調べた方が良いかもしれません。
  • Circuit Breaker自体のコスト: 依存サービスを呼び出すたびに、Circuit Breakerの状態保存、判断処理が走っているから、コストかかります。リモートの呼び出しなら、そのコストの割合が低いから問題ないはずだが、メモリデータの操作等ローカル処理なら、コスト高すぎるので使わない方が良いかもしれません。
  • Circuit Breaker状態保存先の選択: メモリに置いたら一番速いですが、呼び出し側は複数サーバー、複数インスタンスで動くなら、情報共有しにくいから、効果が薄いし反応が遅い問題があります。RDBMS/NOSQLに置くなら、パフォーマンス、storage自体の可用性問題等も考慮しないといけないから、業務要件に合わせて決めましょう。どっちにしても、判断処理のprocess safe、thread safeを注意しないといけません。

以上
次の記事
« Prev Post
前の記事
Next Post »
Related Posts Plugin for WordPress, Blogger...