Hystrix試す
Hystrix: Latency and Fault Tolerance for Distributed Systems
外部リソースに依存したサービスを提供する際、その外部サービスの異常時にこちらのサービスまで影響を受けてしまう事がある。エラーはエラーとして扱うべきなのは当然なのだが、怖いのはダウンした外部リソースへのリクエストに共有リソース(リクエスト処理スレッド、DBコネクション等)が占有されて、他の正常処理可能なリクエストまで巻き込まれてしまう事である。
Hystrixでは初めに外部リソースに対する処理を異なるThreadGroupへ分離させる。これにより異なるサービスに対する共有リソースが占有される事を避ける。さらに異常検知システムが組み込まれており、検知時にはcircuit breakerが起動し、リクエストを投げるような正常処理を行わずに即座にfallback処理を実行するようになる。これにより長時間のリソース占有も回避する事が出来るようになる。
try
提供するサービス、正常なAPIサーバ、定期的に落ちるAPIサーバの3つを用意し試してみる。サービスから正常なAPIサーバと定期的に落ちるAPIサーバに対し異なるThreadPoolを設定し、リクエストを投げるコマンドを用意する。デフォルト設定では以下のようにThreadGroup毎に10個のThreadが利用されている事が分かる。
定期的に落ちるAPIサーバでは、リクエストを受け取りログに流す。エラーを返し始める(画像ではfalseとなっているもの)と本体サーバ側でcircuit breakerが起動し、APIサーバへリクエストを送るのをやめる。一定間隔でリクエストが届くかを確認して届くようになったらcircuit breakerを閉じて通常のリクエストを投げる状態へ戻る。デフォルト設定ではcircuitBreaker.errorThresholdPercentage=50
により50%以上のリクエストが失敗した祭にcircuit breakerが起動するようになっており、circuitBreaker.sleepWindowInMilliseconds=5000
から、5秒毎に疎通確認をしている。
コマンドの様子はhystrix-dashboardでリアルタイムに確認出来る。これはcurcuit breakerが起動しているかのみならず、コマンドの成功数やコマンドの実行にかかる時間(percentileなど)も表示してくれる。
hystrix-dashboardではhystrix-metrics-event-streamから吐かれるstreamを表示するわけだが、Netflix/Turbine · GitHubを用いれば複数台に跨るstreamを集約する事も可能になる。
詳しくはDashboard · Netflix/Hystrix Wiki · GitHubを読めば良い。
導入
既に存在するAPIリクエスト等をHystrixCommand
で包んであげる。問い合わせるサーバ別にThreadGroupを別にすると良いが、もちろんその中にも主要なAPIなどがあると思うので、さらに小分けにThreadGroupを分けても良い。fallback時の対応として、例外を投げるもの、空を返すもの、異なるサービスに問い合わせるものなどあるため適宜対応する。HystrixBadRequestException
で包んで例外を投げるとfallbackされないし、getCause
で原因となる例外を取得する事が出来る。hystrix-metrics-event-streamを入れて、HystrixMetricsStreamServlet
を適当にmappingする。
設定はConfiguration · Netflix/Hystrix Wiki · GitHubを見る。coreSize
、timeoutInMilliseconds
あたりは見ておきたい。coreSize
(= core thread-pool size)は以下の計算式で得られる値を設定すると良いらしい。具体例なども書いているのでThreadPool Propertiesはしっかりと読むべき。
requests per second at peak when healthy × 99th percentile latency in seconds + some breathing room
まぁ、https://github.com/Netflix/Hystrix/wikiが良く書かれているので、全部読んだら良い。
〆
障害対応用の設定が障害を起こすような事だけは避けたい