マイクロサービスを実現するときに Envoy の「サーキットブレーカー (Circuit Breaking)」はよく話題に挙がる.Try Envoy には「サーキットブレーカー」を試すコンテンツがなく,今回ドキュメントを読みながら検証環境を構築し,動作確認をした.もし Try Envoy に興味があったら以下の記事を読んでもらうと良いかなと!
Learn Envoy : Circuit Breaking を読む
試す前に概要を整理するため,今回は Learn Envoy のドキュメントを読んだ.まず,マイクロサービスを運用するときに「連鎖的な障害」を防ぐために「サーキットブレーカー」を使うべきと書いてある.そして,単純な「閾値」によってリクエストを制御するのではなく,プライオリティ機能を使って,例えば「購入などの重要な POST 処理」を優先するなど,実践的なアドバイスも載っている.
さらに,Envoy の Route 側に設定する「自動リトライ機能」を使って,例えばレスポンスコードが 5xx
のときにリトライすることもできるし,サーキットブレーカーに設定する max_retries
によって,Cluster 側でリトライすることもできる.ただし,リトライをするとリクエスト数も増えるため,必要性は適切に検討する必要がある.
circuit_breakers
で使えるパラメータ
「サーキットブレーカー」を使う場合,Envoy の設定ファイル envoy.yaml
の Cluster 設定に circuit_breakers
を追加する.使えるパラメータの概要を以下に載せる.詳細はドキュメントを見てもらえればと.retry_budget
や track_remaining
など,ドキュメントを読んでもよく理解できなかったパラメータもある.
priority
:DEFAULT
とHIGH
のプライオリティを設定する(デフォルトDEFAULT
)max_connections
: 最大コネクション数を設定する (HTTP/1.1 用)max_pending_requests
: 最大保留リクエスト数を設定する(デフォルト1024
)max_requests
: 最大リクエスト数を設定する (HTTP/2 用)max_retries
: 最大リトライ回数を設定する(デフォルト3
)retry_budget
: 最大リトライ回数を上書きしてリトライ予算を設定する(?)track_remaining
: サーキットブレーカーのリソース数をメトリクスとして取得できるようにする(?)max_connection_pools
: 最大コネクション数を設定する(デフォルト 上限なし)
検証環境
実際に検証環境を構築し,動作確認をした.今回は Docker Compose で「Envoy コンテナ(フロントエンド)」と「Sinatra コンテナ(バックエンド)」を起動し,Sinatra では単純に文字列を返すプロトタイプ実装にした.
get '/' do 'Hello!' end
構成図は以下のようになる.
負荷テスト : Vegeta
今回は Vegeta を使って負荷テストを行う.-rate
オプションに秒間のリクエスト数を指定し,-duration
オプションに継続する時間を指定する.レポートを生成できたり,グラフをプロットできたり,便利な機能が多くあるため,個人的によく使っている.
検証結果
簡単に「サーキットブレーカー」を試す場合,envoy.yaml
を以下のように書く.今回は負荷を低く 5
にした.なお,パラメータの概要に載せた通り HTTP/1.1 と HTTP/2 は仕組みが異なるため,対象とするパラメータも異なる.HTTP/1.1 の場合は max_connections
を使って,HTTP/2 の場合は max_requests
を使う.今回は HTTP/1.1 を使うため,基本的には max_connections
の値に依存する.そして,保留リクエストをプールする max_pending_requests
の値はデフォルト 1024
で検証用途だと大きいため,今回は 128
にした.
(中略) clusters: - name: backend connect_timeout: 0.25s type: STRICT_DNS dns_lookup_family: V4_ONLY lb_policy: ROUND_ROBIN circuit_breakers: thresholds: max_connections: 5 max_requests: 5 max_pending_requests: 128 (中略)
検証結果 : -rate=5
と -duration=1m
まず,Vegeta を使って -rate=5
と -duration=1m
で負荷をかけると,問題なく実行できた.Status Codes の部分を見ると 200:300 となり,300件全てのレスポンスコードが 200
だった.そして vegeta report
の結果だと時系列データが確認できないため,今回は jaggr
と jplot
を組み合わせてグラフも生成した.
$ echo 'GET http://localhost:8080' | vegeta attack -rate=5 -duration=1m | tee result.bin | vegeta encode | \ jaggr hist\[200,500\]:code | \ jplot code.hist.200+code.hist.500 $ cat result.bin | vegeta report Requests [total, rate, throughput] 300, 5.02, 5.02 Duration [total, attack, wait] 59.804635434s, 59.797234263s, 7.401171ms Latencies [mean, 50, 95, 99, max] 12.469781ms, 9.218021ms, 28.394007ms, 82.423598ms, 116.723594ms Bytes In [total, mean] 1800, 6.00 Bytes Out [total, mean] 0, 0.00 Success [ratio] 100.00% Status Codes [code:count] 200:300 Error Set:
検証結果 : -rate=20
と -duration=1m
次に,Vegeta を使って -rate=20
と -duration=1m
で負荷を上げてみても,問題なく実行できた.Status Codes の部分を見ると 200:1200 となり,1200件全てのレスポンスコードが 200
だった.
$ $ echo 'GET http://localhost:8080' | vegeta attack -rate=20 -duration=1m | tee result.bin | vegeta encode | \ jaggr hist\[200,500\]:code | \ jplot code.hist.200+code.hist.500 $ cat result.bin | vegeta report Requests [total, rate, throughput] 1200, 20.02, 20.01 Duration [total, attack, wait] 59.965268845s, 59.951868329s, 13.400516ms Latencies [mean, 50, 95, 99, max] 53.635778ms, 15.593157ms, 228.294851ms, 572.832074ms, 714.658048ms Bytes In [total, mean] 7200, 6.00 Bytes Out [total, mean] 0, 0.00 Success [ratio] 100.00% Status Codes [code:count] 200:1200 Error Set:
検証結果 : -rate=50
と -duration=1m
最後に,Vegeta を使って -rate=50
と -duration=1m
で負荷をかけると,サーキットブレーカーの機能によって,一部のレスポンスコードが 503
になった.そしてグラフを見ると,途中から 503
が増えている.これはリトライと保留リクエストの結果だと考えられる.
$ echo 'GET http://localhost:8080' | vegeta attack -rate=50 -duration=1m | tee result.bin | vegeta encode | \ jaggr hist\[200,500\]:code | \ jplot code.hist.200+code.hist.500 $ cat result.bin | vegeta report Requests [total, rate, throughput] 3000, 50.02, 42.52 Duration [total, attack, wait] 1m3.498684051s, 59.979999578s, 3.518684473s Latencies [mean, 50, 95, 99, max] 2.355218631s, 2.643233064s, 3.520133351s, 3.722747469s, 3.787535824s Bytes In [total, mean] 40500, 13.50 Bytes Out [total, mean] 0, 0.00 Success [ratio] 90.00% Status Codes [code:count] 200:2700 503:300 Error Set: 503 Service Unavailable
まとめ
今回は Envoy の「サーキットブレーカー (Circuit Breaking)」を検証するため,Mac に Docker Compose で検証環境を構築し,さらに Vegeta も Mac で実行した.リクエスト数も少なく,実用的な負荷テスト環境とは言えないけど,お手軽に試せたのは良かった.とは言え,パラメータチューニングは難易度が高そうに感じた.「サーキットブレーカー」に求めるシナリオなどを検証し,繰り返し検証をするのが良さそう.検証環境の設定などは全て GitHub に置いておいた.