サーキットブレーカーパターンの仕組み


サーキットブレーカーの状態遷移 Closed リクエスト通過 失敗をカウント中 Open リクエスト遮断 即座にエラー返却 Half-Open テストリクエスト 少数だけ通して確認 失敗がしきい値超過 タイムアウト経過 テスト成功 テスト失敗 正常 遮断中 確認中
サーキットブレーカーの3つの状態遷移のイメージ
ひよこ ひよこ

サーキットブレーカーって、あの電気のブレーカーと関係あるの?

ペンギン先生 ペンギン先生

まさにその電気のブレーカーがモデルだよ。家で電気を使いすぎるとブレーカーが落ちて回路を遮断するよね。ソフトウェアのサーキットブレーカーパターンも同じ発想で、呼び出し先のサービスが調子悪いときにリクエストを遮断して、障害が広がるのを防ぐ仕組みなんだ。

ひよこ ひよこ

障害が広がるってどういうこと?

ペンギン先生 ペンギン先生

たとえばマイクロサービスで、サービスAがサービスBを呼んで、BがCを呼んでいるとする。Cがダウンしたとき、Bは何度もCを呼んで待ち続けるよね。するとBも遅くなって、最終的にAも巻き込まれて全部止まる。これがカスケード障害(障害の連鎖)だよ。

ひよこ ひよこ

全部止まっちゃうのは怖いね…。サーキットブレーカーはどうやって防ぐの?

ペンギン先生 ペンギン先生

サーキットブレーカーには3つの状態があるんだ。まず「Closed(閉)」は通常運転で、リクエストがそのまま通る。失敗が一定回数を超えると「Open(開)」に切り替わって、リクエストを即座にブロックする。しばらく待ってから「Half-Open(半開)」になって、少しだけ試しにリクエストを通す。成功すればClosedに戻るし、失敗すればまたOpenに戻るんだよ。

ひよこ ひよこ

Openのときはリクエストが全部ブロックされるの?ユーザーにはどう見えるの?

ペンギン先生 ペンギン先生

そこで大事になるのがフォールバック戦略だね。たとえばキャッシュされた前回のレスポンスを返す、デフォルト値を返す、「ただいま混み合っています」と表示する、といった方法があるよ。完全にエラーを返すよりずっとユーザー体験がいいよね。

ひよこ ひよこ

なるほど!でも、いつOpenに切り替えるかはどうやって決めるの?

ペンギン先生 ペンギン先生

失敗しきい値とタイムアウトを設定するんだ。たとえば「直近10回のリクエストで5回失敗したらOpenにする」「Openになったら30秒間ブロックしてからHalf-Openにする」みたいにね。この値はサービスの特性に合わせてチューニングするのが重要だよ。

ひよこ ひよこ

実際にコードで使うときはどうするの?自分で書くのは大変そう…。

ペンギン先生 ペンギン先生

ライブラリがあるから大丈夫だよ。JavaならResilience4j、.NETならPolly、GoならSony製のgobreaker が有名だね。以前はNetflixが作ったHystrixが定番だったけど、今はメンテナンスモードになっているよ。

ひよこ ひよこ

Netflixが作ったんだ!さすが大規模サービスだね。

ペンギン先生 ペンギン先生

Netflixは何百ものマイクロサービスを運用していて、Hystrixで障害の連鎖を防いでいたんだ。ただ、今はIstioなどのサービスメッシュ側でサーキットブレーカーを実装する流れに移っていて、アプリケーションコードから切り離す方向に進んでいるよ。

ひよこ ひよこ

サーキットブレーカーの状態って、運用中にどうやって確認するの?

ペンギン先生 ペンギン先生

モニタリングが超重要だよ。Openに切り替わった回数、Half-Openでの成功率、フォールバックの発生頻度をダッシュボードで可視化するのが定石。サーキットブレーカーが頻繁にOpenになるなら、呼び出し先のサービス自体を修正すべきサインだからね。

ひよこ ひよこ

リトライと組み合わせたりもするの?

ペンギン先生 ペンギン先生

いい質問だね。リトライタイムアウトサーキットブレーカーは3点セットで考えるのが基本だよ。まずタイムアウトで1回の待ち時間を制限して、失敗したら数回リトライして、それでもダメならサーキットブレーカーが開いて全体を守る。ただしリトライサーキットブレーカーの設定が噛み合ってないと、リトライが失敗カウントを一気に増やしてすぐOpenになっちゃうから注意が必要だよ。

ひよこ ひよこ

他にも似たパターンってあるの?

ペンギン先生 ペンギン先生

バルクヘッドパターンという補完的な仕組みがあるよ。船の隔壁(バルクヘッド)と同じ発想で、スレッドプールや接続プールをサービスごとに分離するんだ。サーキットブレーカーが「壊れたサービスへの呼び出しを止める」のに対して、バルクヘッドは「壊れたサービスがリソースを食い尽くすのを防ぐ」。両方組み合わせると、マイクロサービスの耐障害性がグッと上がるよ。