AkkaのCircuitBreakerとNetflixのHystrixの違い
2016-12-03
QiitaJavaScalaAkkaこの記事はなに?
マイクロサービス等の文脈で登場するCircuitBreaker。 Scala で使えるものの代表(要出典)として以下の 2 つを比較する。
- Circuit Breaker - Akka Documentation
- シンプルだが単機能
- Netflix/Hystrix
- 高機能
ちなみに個人的な好みは Akka の方。 Scala から使いやすいのと導入が簡単。
CircuitBreaker ってどんなもの?
以前書いたので貼っておきます。 [Akka]CircuitBreaker はどう動くのか - Qiita
Akka の CircuitBreaker
akka.pattern.CircuitBreaker
に状態遷移の条件に当たるもの(maxFailures
, callTimeout
, resetTimeout
)を渡してインスタンス化する。
そしてCircuitBreaker#withCircuitBreaker
にscala.concurrent.Future
を引数として与えるだけ。
一行抜粋するとこんな感じ。
breaker.withCircuitBreaker(Future(dangerousCall)) pipeTo sender()
withCircuitBreaker
でFuture
の実行を監視し、成功したら結果をFuture
として取得する。
規定回失敗したらOpen
に遷移して...という CircuitBreaker らしい機能を提供している。
これの嬉しい点は引数としてscala.concurrent.Future
を要求するところで、監視対象の処理は Akka や Actor には依存しない。
CircuitBreaker
のコンストラクタにakka.actor.Scheduler
を要求する程度。
機能もシンプルな CircuitBreaker という程度で、Future
の監視以外は何も提供されていない。
ThreadPool はコンストラクタのExecutionContext
として設定することになる。
Hystrix
Akka の CircuitBreaker と違って、実行を監視する存在がいるのではなく、監視対象となる処理自体をHystrixCommand
として定義・実装する点が大きく違う。
一行抜粋するとこんな感じ。
String s = new CommandHelloWorld("Bob").execute();
execute
以外にもjava.util.concurrent.Future
を返却するqueue()
やrx.Observable
を返却するobserver()
がある。
Future<String> s = new CommandHelloWorld("Bob").queue();
Observable<String> s = new CommandHelloWorld("Bob").observe();
getFallback
を定義しておくことでexecute
等が失敗した際の fallback 値を返却する機能もある。
処理そのものをHystrixCommand
として定義するのはすっきりして良い。
外部からはexecute
のような処理の kick しか出来ないので、必要な情報を詰め込んでおける。
ここでは詳しくあげないが、Command 実行時のMetricsを取得できたりダッシュボードが用意してあったりキャッシュも組み込んであったりと色々出来る。 高機能過ぎる...。
あと、そもそも CircuitBreaker で監視したい対象は、外部サービスを非同期に呼び出す処理だったりすることが多い。
なので非同期呼び出し前提としてexecute
は無くても良さそう。
CircuitBreaker としての Hystrix
機能が盛り沢山な Hystrix だが、今回は CircuitBreaker として見てみる。 設定出来る項目は以下を参照。 Configuration · Netflix/Hystrix Wiki
実際に設定を適用するにはこんな感じ。
object MyCommand {
val key = HystrixCommandGroupKey.Factory.asKey("my-command")
private val circuitBreakerSetter =
HystrixCommandProperties.Setter()
.withCircuitBreakerEnabled(true)
.withCircuitBreakerRequestVolumeThreshold(10)
.withCircuitBreakerErrorThresholdPercentage(30)
.withCircuitBreakerSleepWindowInMilliseconds(50)
val setter: HystrixCommand.Setter =
HystrixCommand.Setter
.withGroupKey(key)
.andCommandPropertiesDefaults(circuitBreakerSetter)
}
class MyCommand(num: Long) extends HystrixCommand[Result](MyCommand.setter) {
???
}
Akka の何回失敗したら、という設定と異なり、一定時間内にどの程度(%)失敗したら Open になる、という設定の仕方。
ざっくり比較
Akka の CircuitBreaker は非常にシンプルだが機能は少ない。
繰り返しになるが単なるscala.concurrent.Future
を監視出来る手軽さは強力かなと。
設定出来る項目も少なく、学習コストは低いと思われる。
導入も捨てるのも簡単なので総合的にお手軽。
それに対して Hystrix は高機能だがやや複雑な印象。
ダッシュボードやキャッシュといった機能だけでなく ThreadPool やタイムアウトの設定なども細かく出来る。
使い込めばかなり便利そう。
もちろん、単純にHystrixCommand
を実装したコマンドを使うだけなら簡単。
とりあえず CircuitBreaker としての機能が必要なら Akka で、 ダッシュボード等の機能も必要であれば Hystrix を使う。
ちなみに Akka の方でもこんな Issue が立ってたりで面白い。 CircuitBreaker should provide statistics like Netflix Hystrix does · Issue #16617 · akka/akka
Scala 的な観点
あまり言いたくないが Hystrix の難点は Java であることで、Scala から使うという観点に立つとObservable
はともかくjava.util.concurrent.Future
は使いづらい。
scala.concurrent.Promise
使うとかjava.util.concurrent.Future#get
をscala.concurrent.Future#apply
で非同期にするとか...?
多少頑張れば Scala からでもいい感じに使えそう。 Hystrix を Scala / Play アプリケーションから使ってみる - たけぞう瀕死ブログ
ちなみにObservable
はScala2.12 の SAMのおかげで以下のように簡潔に使えるようになっているのが嬉しい。
command.observe().subscribe(
(r: Result) => doSomething(r), // onNext
(t: Throwable) => t.printStackTrace(), // onError
() => println("complete") // onComplete
)
from: https://qiita.com/petitviolet/items/f1975fba06655a95e3b0