狠狠撸

狠狠撸Share a Scribd company logo
Developing an Akka Edge
Chapter 6
前回のおさらい
(Chapter 6の前に…)
?結局…
アクターはメッセージを到着した順に1つずつ処理する
メッセージが来たら、あらかじめ定義されたふるまいを実行する
Putting actors to work
アクターを使うのにまず必要な事
?akka.actor.Actorトレイトを継承したクラスと、そこにreceiveメソッドを定義
?ActorSystemを作る
?ActorSystemからアクターを生成
メッセージの送り方② ask
Futureを返す
Futureが含んでいる値(処理済/まだ処理されていない/永遠に処理されない)
   永遠に処理されない可能性もあるので、implicit valを使って時間を設定
アクターへ送るメッセージは非同期なので、アクター以外のコード内でレスポンスを得
るにはFutureを使う必要がある
Developing an Akka Edge
Chapter 6
Developing an Akka Edgeだけでは理解できない部分があったため、
AkkaとJavaのDocument
Let it crash
Akka Concurrency
Java言語で学ぶデザインパターン入門
も参考にしました。
(今回はもはや本の要約じゃないです)
これまでと同様に
自分が持っていた知識やいくつかの情報を元にまとめたり、
不慣れな英語を読み進めているため正しくない項目がある可能性があります。
Chapter 6.Dispatchers
*この章のポイント*
?いろんな顿颈蝉辫补迟肠丑别谤といろんなパラメータ
2つのexecutor(Fork/JoinとThreadPoolExecutor)
?いろんなMailboxとパラメータ
?ざっくりした使用例とチューニングについて
Chapter 6.Dispatchers
DispatcherとRouterは全然別物!!
Dispatcherのコンセプト
アクターが処理を実行する時のスレッド割当
スレッドプールを持っていて、スレッドをアクターに割り当てる
導入
Dispatcherを使うと…?
Low latency
例:特定のActorに1スレッド丸ごと割り当てると…
Low latency
例:特定のActorに1スレッド丸ごと割り当てると…
スレッドが割り当てられるのを待たなくて良いので
メッセージをすぐ処理してくれる
Bulkhead Pattern
例:IO処理と計算処理のActor達を別のDispatcherにすると…
Bulkhead Pattern
例:IO処理と計算処理のActor達を別のDispatcherにすると…
計算処理Dispatcherのスレッド数を多くするなど
IO と 计算のどっちに比重を置くかチューニングができる
Dispatcherのメリット
システムのある一部において
応答性UP
負荷分散
パフォーマンスUP
チューニング
が可能!!
(また、耐障害性もUP?)
顿颈蝉辫补迟肠丑别谤の设定
顿颈蝉辫补迟肠丑别谤の设定
デフォルトの設定
default-dispatcher{
type=Dispatcher
executor="fork-join-executor"
throughput=10
fork-join-executor{
parallelism-min=4
parallelism-max=32
parallelism-factor=4.0
}
}
顿颈蝉辫补迟肠丑别谤の设定
デフォルトの設定
default-dispatcher{
type=Dispatcher
executor="fork-join-executor"
throughput=10
fork-join-executor{
parallelism-min=4
parallelism-max=32
parallelism-factor=4.0
}
}
← Dispatcherの名前
後でコード上から呼び出す時に使う。
好きな名前で
顿颈蝉辫补迟肠丑别谤の设定
デフォルトの設定
default-dispatcher{
type=Dispatcher
executor="fork-join-executor"
throughput=10
fork-join-executor{
parallelism-min=4
parallelism-max=32
parallelism-factor=4.0
}
}
← Dispatcherの種類
Dispatcher
PinnedDispatcher
BalancingDispatcher
CallingThreadDispatcher
から選ぶ
顿颈蝉辫补迟肠丑别谤の设定
デフォルトの設定
default-dispatcher{
type=Dispatcher
executor="fork-join-executor"
throughput=10
fork-join-executor{
parallelism-min=4
parallelism-max=32
parallelism-factor=4.0
}
}
←executorの種類
fork-join-executor
thread-pool-executor
から選ぶ
並列処理の実行の仕方が違う
顿颈蝉辫补迟肠丑别谤の设定
デフォルトの設定
default-dispatcher{
type=Dispatcher
executor="fork-join-executor"
throughput=10
fork-join-executor{
parallelism-min=4
parallelism-max=32
parallelism-factor=4.0
}
}
← throughput
この値は、
Actorにスレッドを割り当てた時
1回あたりいくつのメッセージを処理するか
(終わったらスレッドプールに戻る)
throughputとfairness
throughput = 1の時
Actor1のメッセージを1つ処理
Actor2の…
Actor3の…
Actor1の…
Actor3のMailboxが最初に空になる
throughputとfairness
throughput = 100の時
Actor1のメッセージを100つ処理
Actor2の…
Actor3の…
Actor1のMailboxが最初に空になる
throughput = 1だと公平にメッセージを処理できるが、
切り替えが頻繁に起こるとパフォーマンスが悪くなる
顿颈蝉辫补迟肠丑别谤の设定
デフォルトの設定
default-dispatcher{
type=Dispatcher
executor="fork-join-executor"
throughput=10
fork-join-executor{
parallelism-min=4
parallelism-max=32
parallelism-factor=4.0
}
}
← このへんは
スレッド数の設定的な感じ
thread-pool-executorを使う時は別の項目
Fork/Join
と
ThreadPoolExecutor
Fork/Joinとは
タスクを分割していって、それらを並列に処理していくフレームワーク
Java7から導入された
a + b + c + d
ちゃんと理解してないので雑な説明 …
Fork/Joinとは
タスクを分割していって、それらを並列に処理していくフレームワーク
Java7から導入された
a + b = e c + d = f
a + b + c + d
ちゃんと理解してないので雑な説明 …
Fork/Joinとは
タスクを分割していって、それらを並列に処理していくフレームワーク
Java7から導入された
e + f
a + b = e c + d = f
ちゃんと理解してないので雑な説明 …
Fork/Joinとは
タスクを分割していって、それらを並列に処理していくフレームワーク
Java7から導入された
タスクを細分化して…というのがActorの設計と似ているので、相性が良い
fork-join-executorの設定
default-dispatcher{
type=Dispatcher
executor="fork-join-executor"
throughput=10
fork-join-executor{
parallelism-min=4
parallelism-max=32
parallelism-factor=4.0
}
}
CPUのコア数×factor
?並列実行するスレッド数
ただし、min < スレッド数 < max
ThreadPoolExecutorとは
java.util.concurrent.ThreadPoolExecutor
ワーカスレッドを管理するクラス
タスクキューを持っていて
スレッドプールのスレッドを使ってタスクを実行
?終わったらスレッドプールにスレッドがもどる
というのを繰り返している
スレッド
thread-pool-executorの設定
my-thread-dispatcher{
type=Dispatcher
executor="thread-pool-executor"
thread-pool-executor{
core-pool-min = 4
core-pool-max = 32
core-pool-factor = 2.0
max-pool-min = 8
max-pool-max = 84
max-pool-factor = 3.0
keep-alive-time = 30ms
task-queue-type = “linked”
}
core-poolとmax-pool
それぞれの設定がある
corePoolとmaxPool
新しいタスクが、キューに追加された時
①corePoolSize > 実行中のスレッド数
新しいスレッドが作成される
②corePoolSize < 実行中のスレッド数 < maxPoolSize
キューが一杯の時のみ新しいスレッドが作成される
③maxPoolSize == 実行中のスレッド数
キューが一杯ならタスクがrejectされる
keep-alive-time
corePoolSize < 実行中のスレッド数 の時
タスクキューが空で暇なスレッドがあったら…
アイドル状態がkeep-alive-timeを超えるとスレッドが終了する
task-queue-type
LinkedBlockingQueue(サイズ上限なし)
ArrayBlockingQueue(サイズ上限指定)
から選ぶ
※LinkedBlockingQueueを使うと、corePoolSizeの全てのスレッドがbusy状態の時
新しいタスクはキュー内にどんどんたまっていくので
corePoolSizeを超えるスレッドは作成されない※
大きなキューと小さなプールを使用すると、スループットが低下する恐れあり
(CPU使用率?context switchingのオーバーヘッドは最小化される)
thread-pool-executorの設定
my-thread-dispatcher{
type=Dispatcher
executor="thread-pool-executor"
thread-pool-executor{
core-pool-min = 4
core-pool-max = 32
core-pool-factor = 2.0
max-pool-min = 8
max-pool-max = 84
max-pool-factor = 3.0
keep-alive-time = 30ms
}
}
いろんな顿颈蝉辫补迟肠丑别谤
いろんな顿颈蝉辫补迟肠丑别谤
Dispatcher
デフォルトで使っている
PinnedDispatcher
BalancingDispatcher
CallinThreadDispatcher
akka.testkitに入ってるので、9章で登場するかも!?
いろんな顿颈蝉辫补迟肠丑别谤
Dispatcher
デフォルトで使っている
PinnedDispatcher
BalancingDispatcher
CallinThreadDispatcher
akka.testkitに入ってるので、9章で登場するかも!?
PinnedDispatcher
それぞれのアクターに1スレッドずつ割り当てる。
?全てのアクターがスレッドをフルに使える
特に優先度が高いリソースを持っている時に使う
※このパターンを使いすぎないように!!※
BalancingDispatcher
1つのMailboxをシェアしている。
暇になったActorがメッセージを処理するので、負荷は公平
全て同じ型のActorと使う事を想定されている
(型が違っても、受け取れるメッセージが同じなら動きそう)
6种の惭补颈濒产辞虫
6种の惭补颈濒产辞虫
UnboundedMailbox
SingleConsumerOnlyUnboundedMailbox
BoundedMailbox
UnboundedPriorityMailbox
BoundedPriorityMailbox
Durable
6种の惭补颈濒产辞虫
UnboundedMailbox
SingleConsumerOnlyUnboundedMailbox
BoundedMailbox
UnboundedPriorityMailbox
BoundedPriorityMailbox
Durable 1つのActorに1つのMailbox
(デフォルトはこれ)
他のMailboxが全部シェアしているのかは未確認です …
6种の惭补颈濒产辞虫
UnboundedMailbox
SingleConsumerOnlyUnboundedMailbox
BoundedMailbox
UnboundedPriorityMailbox
BoundedPriorityMailbox
Durable Mailboxの容量が
有限 or 无限
6种の惭补颈濒产辞虫
容量が有限の時のパラメータ
mailbox-capacity
Mailboxの容量
mailbox-push-timeout-time
Mailboxが一杯の時、空くのを待つ時間(?)
-1にすると无限
6种の惭补颈濒产辞虫
UnboundedMailbox
SingleConsumerOnlyUnboundedMailbox
BoundedMailbox
UnboundedPriorityMailbox
BoundedPriorityMailbox
Durable Mailbox内のメッセージに
優先度付き
6种の惭补颈濒产辞虫
extendsして使う
Intで優先度を指定
(0が優先度最高)
6种の惭补颈濒产辞虫
UnboundedMailbox
SingleConsumerOnlyUnboundedMailbox
BoundedMailbox
UnboundedPriorityMailbox
BoundedPriorityMailbox
Durable Mailboxのメッセージを
永続化できる
(ファイルシステム)
ここまで長くなりましたが…
実際にDispatcherを使う
Dispatcherを使う
①ActorにDispatcherを設定する場合
val myActor = system.actorOf(Props[MyActor].withDispatcher(“my-dispatcher”))
Actorの設定をconfigurationに書いていれば、withDispatcherを使わなくてもよい
val myActor = system.actorOf(Props[MyActor],”myactor”)
akka.actor.deployment{
/myactor{
dispatcher = my-dispatcher
}
}
Dispatcherを使う
②FutureのためにDispatcherを使う場合
implicit val executionContext = system.dispatchers.lookup(“my-dispatcher”)
Mailboxを使う
myMailbox{
mailbox-type = “BoundedMailbox”
mailbox-capacity = 1000
mailbox-push-timeout-time = 1
}
val myActor = system.actorOf(Props[MyActor].withMailbox(“myMailbox”)
Dispatcherの時と同様に、akka.actor.deployのActorの設定内に書いてもよい
使用例
Akka Concurrencyの
When to choose a dispatching method参照
Low latency ? PinnedDispatcherを使う
例:特定のActorに1スレッド丸ごと割り当てると…
スレッドが割り当てられるのを待たなくて良いので
メッセージをすぐ処理してくれる
Bulkhead Pattern ? Dispatcherを使う
例:IO処理と計算処理のActor達を別のDispatcherにすると…
計算処理Dispatcherのスレッド数を多くするなど
IO と 计算のどっちに比重を置くかチューニングができる
cruch…ボリボリ噛む
なるべく全てのActorをbuzyにしたい時
Number cruching ? 叠补濒补苍驳颈苍驳顿颈蝉辫补迟肠丑别谤を使う
IO処理が伴うので、Durableを使う時は他のアクターと分離させる
Message durability? DurableとDispatcherを使う
チューニングについて
Let it crashの
Tuning Dispatchers in Akka Applications参照
顿颈蝉辫补迟肠丑别谤の设定
デフォルトの設定
default-dispatcher{
type=Dispatcher
executor="fork-join-executor"
throughput=10
fork-join-executor{
parallelism-min=4
parallelism-max=32
parallelism-factor=4.0
}
}
なんやかんや言っても
デフォルト設定で良い場合が多い
Typesafe Consoleでチェック
Dispatcher view でメッセージハンドリングのlatency、mailbox-sizeなどが見れる
(ちゃんと調べてませんが、現在は無料で使えないようです…)
profilingしてheavy computationな部分を特定し
?RouterとBalancingDispatcherを使って外に出す
mailbox sizeが増え続けているならRouterを作った方がよい
デフォルトでもスレッド数の上限が決まっているので、
コア数を増やしても別のDispatcherを使わないと
futureがタイムアウトになったり、スループットが上がらない
type
デフォルトの設定
default-dispatcher{
type=Dispatcher
executor="fork-join-executor"
throughput=10
fork-join-executor{
parallelism-min=4
parallelism-max=32
parallelism-factor=4.0
}
}
← Dispatcherの種類
最優先処理がある場合PinnedDispatcher
(よっぽど特別な場合だけ使用する)
負荷分散したい時はRouterとBalancingDispatche
executor
デフォルトの設定
default-dispatcher{
type=Dispatcher
executor="fork-join-executor"
throughput=10
fork-join-executor{
parallelism-min=4
parallelism-max=32
parallelism-factor=4.0
}
}
←executorの種類
fork-join-executorの方が良い
(PinnedDispatcherはthread-pool-のみ)
Let it crashの記事より、thread-poolからfork-joinにしたら1100%増になった
Throughput比較
task-queueへのアクセス/ロックが多い ? context switchingが発生しやすい
throughput
デフォルトの設定
default-dispatcher{
type=Dispatcher
executor="fork-join-executor"
throughput=10
fork-join-executor{
parallelism-min=4
parallelism-max=32
parallelism-factor=4.0
}
}
← throughput
Actor数≒スレッド数なら多め
時間のかかるタスクが多いなら少なめ
(頻繁に切り替わると時間がかかる)
デフォルト値から初めてチューニングすべし
まとめ
?Actorにスレッドが割り当てられると、数個のメッセージを処理して
 スレッドプールに戻る
?パフォーマンスが悪い部分を別DispatcherとかRouterで切り出す
?Actorを小さく作れば、どのDispatcherに属させるか柔軟にチューニングできそう(チームの先
輩談)

More Related Content

Developing an Akka Edge6