Developing an Akka Edge4-5
Transcript of Developing an Akka Edge4-5
この本について
Developing an Akka Edge(著)Thomas Lockney, Raymond Tay
Akka初心者向けの洋書全191ページ・10章
せっかく読んでるので要約しました※自分で調べた事や、考えた例も載せたのでスライドに正しくないことが書いてある可能性があります※
各章の概要
Chapter 4…SupervisorStrategyを使ったエラーハンドリング
Chapter 5…Routerについていろんな種類のRouterの紹介
Chapter1~3も別スライドにまとめてあります
Putting actors to work
アクターを使うのにまず必要な事
・akka.actor.Actorトレイトを継承したクラスと、そこにreceiveメソッドを定義・ActorSystemを作る
・ActorSystemからアクターを生成
ヒエラルキー
Akkaの構造がヒエラルキーになっている理由⇒耐障害性
親アクターは子アクターにExceptionが発生した時にどうするか決められる・子アクターを再起動させる・子アクターを再開させる・子アクターを終了させる・例外を次の親に投げる
ヒエラルキーはファイルシステム的な感じで、分かりやすい
例:accountingというActorsystemから作られたaccountMonitorというアクターから作られたaccountCrediterというアクター
akka://accounting/user/accountMonitor/accountCreditor
Chapter 4.Handling Faults
and Actor Hierarchy
*この章のポイント*
・ヒエラルキーの中で、どうやってエラーハンドリングをするか
⇒SupervisorStrategy
・アクターのライフサイクル
・アクターのヒエラルキーについて(最上部がどうなってるかとか)
・「Failure happen.」ネットワークの切断、ロジックの間違い、環境の問題…etc
・try/catch
大抵の言語で実装されているが…
エラーが起きた時、システムがどんな状態にあるかを理解しないといけない
通常の状態に戻れたか確認しなければいけない
Chapter 4.Handling Faults
and Actor Hierarchy
Typical failure handling
Scalaのエラーハンドリング①try/catch/finally
例外の種類をcase文で
②Try[T]
例外が投げられたらFailure[T]インスタンスが返ってくる(成功はSuccess[T])
他の処理をチェーンして、成功した時のみ実行できる⇒シンプルに書ける
③Either[A,B]
一般的にAが成功時、Bが失敗時に使われる例外の型をしっていなければいけない
Let it crash
例:アクターが値を保持していて、外部のシステムから値をとってきて定期的に更新しなければならない
Actor
count = 1
System
count = 3Request
{“count”:3}
Let it crash
例:アクターが値を保持していて、外部のシステムから値をとってきて定期的に更新しなければならない
外部から値をとってくる時にエラーが起こる可能性があるconnection timeout, Http failure code responses, expired credentials…
Actor
count = 1
System
count = 3Request
??????
Let it crash
例:アクターが値を保持していて、外部のシステムから値をとってきて定期的に更新しなければならない
外部から値をとってくる時にエラーが起こる可能性があるconnection timeout, Http failure code responses, expired credentials…
子アクターを生成して、外部へのリクエストを分離する
Actor
count = 1
System
count = 3Request
{“count”:3}
Child
Actor
Request
{“count”:3}
Fail fast
・原則、アクターは「なるべく小さく・1つの目的」で使う例外処理のロジックを含まず、エラーが起きたら再起動or作り直す
・Supervisorが鍵となるsupervisor…子アクターにとっての親アクターどんなアクターにも親アクターがいる(最上位については後述)
子アクターが処理できない例外が発生 ⇒ 親がどうするか決める
ActorChild
Actor
Restart! Exception
Fail fast
子アクターが処理できない例外は、親アクターがSupervisorStrategyに沿って処理
2種類のSupervisorStrategy
OneForOneStrategy
AllForOneStrategy
Fail fast
AllForOneStrategy...supervisorの全ての子アクターに適用兄弟アクターが相互依存関係にある時はこっち
Actor
Child
ActorChild
Actor
Child
Actor
Fail fast
子アクターに例外が発生した時Resume… 再開するだけ(内部の状態は保持)
Restart… 全ての状態を再設定して、再起動
Stop… 止まるだけ
Escalate… supervisorの親に拡散Actor
Child
ActorChild
Actor
Child
Actor
Grandpa
Actor
Actor
Fail fast
・Resume,Restartを使う時は、次々同じエラーが出ないかどうか確かめる!
・Resume,Restartについては、何度まで再開・再起動できるか設定できる
60秒間に5回まで(超えるとEscalateされる)
Fail fast
・デフォルトの挙動(strategyが定義されていない時)- Stop
ActorInitializationException(初期化失敗)ActorKilledException(akka.actor.Killメッセージを受信した時)
- Restart
他のException
- Escalate
他のThrowable
*OneForOneStrategyで、Restartの回数に制限なし*
The actor-lifecycle
actorOf(Props[Actorの名前])を呼んだら生成される
起動前・終了前・再起動前後で実行されるメソッド- preStart
- postStop
- preRestart
- postRestart
preStartは初期化系preRestartは相互依存してるリソースを掃除するのに使う
The actor-lifecycle
pre/postRestartは、再起動の原因になったThrowableインスタンスを引数に取る
postRestartはpreStartメソッドを呼んでいるので、overrideする時は呼ぶこと!
The actor-lifecycle
Death Watch
アクターが終了した事を知らせる
アクターが終了したら、ActorRefを持ったTerminatedメッセージが来る
context.watchでアクターを登録
A bit more about the hierarchy
ヒエラルキーの最上位はどうなっているか…
「guardianと呼ばれる」3つの特別なアクター- root guardian
- user guardian
- system guardian
A bit more about the hierarchy
・user guardian
system.actorOf()を使って生成されるアクター達のトップ⇒作ったアクターがハンドリングできなかったエラーは最終的にここに来る
SupervisorStrategyは、akka.actor.guardian-supervisor-startegyで上書きできる
ヒエラルキーはファイルシステム的な感じで、分かりやすい
例:accountingというActorsystemから作られたaccountMonitorというアクターから作られたaccountCrediterというアクター
akka://accounting/user/accountMonitor/accountCreditor
実はChapter.1にも出てた
A bit more about the hierarchy
・system guardian
user-levelのアクターが必要とするサービスを提供(順番にshut-downさせるとか)user guardiaをwatchしてる
・root guardian
ヒエラルキーのトップに存在して、guardianからEscalateされたエラーを処理する
A bit more about the hierarchy
root guardianもアクターなので、supervisorが必要⇒ActorSystemの外側に、疑似アクターのsupervisorが居る
どんなエラーが起きても、子アクター(root guardian)をStopさせる。
Guidelines for handling failures
・危険な処理を隔離して、エラーが起きても良い設計にしよう!
・error kernel pattern…エラーハンドリングを、発生する場所の近くに分散させる
例:DBとのやりとりは、別のアクターにする
Guidlines for handling failures
・更なるアプローチとして特定の役割を持ったアクターと、supervisorをセットで作る
危険な仕事をするアクター + そのアクターを監視するアクター
ロジックを抽象化できる
System
count = 3Request
{“count”:3}
Child
Actor
Supervise
SupervisorStorategy
The basics of routers
・Routerは、アクターへのメッセージの流れを制御するアクターのグループへ、ルールに従ってメッセージを送信する
・Routerは一応アクターだが、Mailboxやメッセージハンドリングは使わない
Router
Routees
Other Actor
The basics of routers
送信元はRouteeなので、返事がRouteeに来てしまう
Router
Routees
Other Actor
sender.tell(SomeMessage())
sender.tell(ResponseMessage())
The basics of routers
送信元を親(Router)にすると…
Router
Routees
Other Actor
sender.tell(SomeMessage(),context.parent)第二引数で送信元を指定
The basics of routers
Routerに送信され、いずれかのRouteeに送信される
Router
Routees
Other Actor
sender.tell(ResponseMessage())
sender.tell(SomeMessage(),context.parent)
Built-in router types
Akkaが提供しているいろんなRouterがある
- RoundRobinRouter
- SmallMailboxRouter
- BroadcastRouter
- RandomRouter
- ScatterGatherFirstCompleteRouter
- ConsistentHashingRouter
- Other(カスタムRouterを自分でつくれる)
Built-in router types
・RoundRobinRouter
メッセージを順番に送信する(どのRouteeから始めるかは指定できない)
Router
Routees
Other Actor
① ② ③
Built-in router types
・RoundRobinRouter
タスクにかかる時間にばらつきがある時は注意!!
A B
Router
① ②
③ ④①
②
③
④
受信したメッセージが処理に時間のかかるものに偏るとAにメッセージが貯まっていってしまう…
Built-in router types
・SmallestMailboxRouter
Mailboxにたまっているメッセージが少ないアクターに送信
Router
Routees
Other Actor
Built-in router types
・SmallestMailboxRouter
Mailboxに今この瞬間どれくらいたまっているか、正確には分からない
情報が古いかもしれない(どのタイミングで取得してるのか謎)
リモートアクターのMailboxサイズは分からない⇒送信の優先順位が低くなる
Built-in router types
・ScatterGatherFirstCompletedRouter
Routeeにブロードキャストして、一番速く返ってきたレスポンスを受け取る
scatter…まき散らす
Router
Routees
Other Actor
fastest
Built-in router types
・ScatterGatherFirstCompleteRouter
askメソッドでRouterからFutureを得るこのRouterはFutureをラップしている
時間に関してsensitiveな場面で使う
Built-in router types
・ConsistentHashingRouter
受け取ったリクエストを、どのサーバに送るか決められる(?)
この話だけでかなりボリュームがあるので、省略
Router
Routees
Other Actor
Using routers
各種パラメータ+ lower-bound
+ upper-bound
+ messages-per-resize
+ pressure-threshold
+ rampup-rate
+ backoff-threshold
+ backoff-rate
+ (stop-delay)
他にもありそう…
Using routers
lower-bound…Routeeの最小数初期のRoutee数になる(?)
upper-bound…Routeeの最大数
messages-per-resize…リサイズの頻度
リサイズに関するパラメータがたくさん…
Using routers
+ pressure-threshold(0)
0 ⇒メッセージを処理中のRouteeはbuzy
1 ⇒メッセージを処理中で、Mailboxにメッセージがあればbuzy
+ rampup-rate(0.2)
全てのアクターがbuzyの時、Routeeをどのくらい増やすか
+ backoff-threshold(0.3)
buzyなRouteeが何割以下になったら、Routeeを減らすか
+ backoff-rate(0.1)
Routeeを減らす時、どのくらい減らすか
Programatic router creation
コード内でRouterを定義するメリット ⇒ SupervisorStrategyを定義できる
デフォルトではRouterはEscalateしかしない
まとめ
・負荷分散とかにいろんな種類のRouterが使える
・Routeeの数に関するパラメータがたくさんあるconfigurationかコードの中に記述する
・Props.withRouterメソッドを使って生成する