Top Banner
Developing an Akka Edge Chapter 6
67

Developing an Akka Edge6

Jul 15, 2015

Download

Software

saaaaaaki
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Developing an Akka Edge6

Developing an Akka EdgeChapter 6

Page 2: Developing an Akka Edge6

前回のおさらい

(Chapter 6の前に…)

Page 3: Developing an Akka Edge6

・結局…アクターはメッセージを到着した順に1つずつ処理する

メッセージが来たら、あらかじめ定義されたふるまいを実行する

Page 4: Developing an Akka Edge6

Putting actors to workアクターを使うのにまず必要な事

・akka.actor.Actorトレイトを継承したクラスと、そこにreceiveメソッドを定義

・ActorSystemを作る

・ActorSystemからアクターを生成

Page 5: Developing an Akka Edge6

メッセージの送り方② ask

Futureを返す

Futureが含んでいる値(処理済/まだ処理されていない/永遠に処理されない)

   永遠に処理されない可能性もあるので、implicit valを使って時間を設定

アクターへ送るメッセージは非同期なので、アクター以外のコード内でレスポンスを得るにはFutureを使う必要がある

Page 6: Developing an Akka Edge6

Developing an Akka EdgeChapter 6

Page 7: Developing an Akka Edge6

Developing an Akka Edgeだけでは理解できない部分があったため、

AkkaとJavaのDocumentLet it crashAkka ConcurrencyJava言語で学ぶデザインパターン入門

も参考にしました。

(今回はもはや本の要約じゃないです)

これまでと同様に

自分が持っていた知識やいくつかの情報を元にまとめたり、

不慣れな英語を読み進めているため正しくない項目がある可能性があります。

Page 8: Developing an Akka Edge6

Chapter 6.Dispatchers

*この章のポイント*

・いろんなDispatcherといろんなパラメータ

2つのexecutor(Fork/JoinとThreadPoolExecutor)

・いろんなMailboxとパラメータ

・ざっくりした使用例とチューニングについて

Page 9: Developing an Akka Edge6

Chapter 6.DispatchersDispatcherとRouterは全然別物!!

Dispatcherのコンセプト

アクターが処理を実行する時のスレッド割当

スレッドプールを持っていて、スレッドをアクターに割り当てる

Page 10: Developing an Akka Edge6

導入Dispatcherを使うと…?

Page 11: Developing an Akka Edge6

Low latency例:特定のActorに1スレッド丸ごと割り当てると…

Page 12: Developing an Akka Edge6

Low latency例:特定のActorに1スレッド丸ごと割り当てると…

スレッドが割り当てられるのを待たなくて良いので

メッセージをすぐ処理してくれる

Page 13: Developing an Akka Edge6

Bulkhead Pattern例:IO処理と計算処理のActor達を別のDispatcherにすると…

Page 14: Developing an Akka Edge6

Bulkhead Pattern例:IO処理と計算処理のActor達を別のDispatcherにすると…

計算処理Dispatcherのスレッド数を多くするなど

IO と 計算のどっちに比重を置くかチューニングができる

Page 15: Developing an Akka Edge6

Dispatcherのメリット

システムのある一部において

応答性UP負荷分散

パフォーマンスUPチューニング

が可能!!

(また、耐障害性もUP?)

Page 16: Developing an Akka Edge6

Dispatcherの設定

Page 17: Developing an Akka Edge6

Dispatcherの設定

デフォルトの設定

default-dispatcher{type=Dispatcherexecutor="fork-join-executor"throughput=10

fork-join-executor{parallelism-min=4parallelism-max=32parallelism-factor=4.0

}}

Page 18: Developing an Akka Edge6

Dispatcherの設定

デフォルトの設定

default-dispatcher{type=Dispatcherexecutor="fork-join-executor"throughput=10

fork-join-executor{parallelism-min=4parallelism-max=32parallelism-factor=4.0

}}

← Dispatcherの名前

後でコード上から呼び出す時に使う。好きな名前で

Page 19: Developing an Akka Edge6

Dispatcherの設定

デフォルトの設定

default-dispatcher{type=Dispatcherexecutor="fork-join-executor"throughput=10

fork-join-executor{parallelism-min=4parallelism-max=32parallelism-factor=4.0

}}

← Dispatcherの種類

DispatcherPinnedDispatcherBalancingDispatcherCallingThreadDispatcher

から選ぶ

Page 20: Developing an Akka Edge6

Dispatcherの設定

デフォルトの設定

default-dispatcher{type=Dispatcherexecutor="fork-join-executor"throughput=10

fork-join-executor{parallelism-min=4parallelism-max=32parallelism-factor=4.0

}}

←executorの種類

fork-join-executorthread-pool-executorから選ぶ

並列処理の実行の仕方が違う

Page 21: Developing an Akka Edge6

Dispatcherの設定

デフォルトの設定

default-dispatcher{type=Dispatcherexecutor="fork-join-executor"throughput=10

fork-join-executor{parallelism-min=4parallelism-max=32parallelism-factor=4.0

}}

← throughput

この値は、Actorにスレッドを割り当てた時1回あたりいくつのメッセージを処理するか(終わったらスレッドプールに戻る)

Page 22: Developing an Akka Edge6

throughputとfairnessthroughput = 1の時

Actor1のメッセージを1つ処理

Actor2の…Actor3の…Actor1の…

Actor3のMailboxが最初に空になる

Page 23: Developing an Akka Edge6

throughputとfairnessthroughput = 100の時

Actor1のメッセージを100つ処理

Actor2の…Actor3の…

Actor1のMailboxが最初に空になる

throughput = 1だと公平にメッセージを処理できるが、

切り替えが頻繁に起こるとパフォーマンスが悪くなる

Page 24: Developing an Akka Edge6

Dispatcherの設定

デフォルトの設定

default-dispatcher{type=Dispatcherexecutor="fork-join-executor"throughput=10

fork-join-executor{parallelism-min=4parallelism-max=32parallelism-factor=4.0

}}

← このへんはスレッド数の設定的な感じ

thread-pool-executorを使う時は別の項目

Page 25: Developing an Akka Edge6

Fork/Joinと

ThreadPoolExecutor

Page 26: Developing an Akka Edge6

Fork/Joinとは

タスクを分割していって、それらを並列に処理していくフレームワーク

Java7から導入された

a + b + c + d

ちゃんと理解してないので雑な説明 …

Page 27: Developing an Akka Edge6

Fork/Joinとは

タスクを分割していって、それらを並列に処理していくフレームワーク

Java7から導入された

a + b = e c + d = f

a + b + c + d

ちゃんと理解してないので雑な説明 …

Page 28: Developing an Akka Edge6

Fork/Joinとは

タスクを分割していって、それらを並列に処理していくフレームワーク

Java7から導入された

e + f

a + b = e c + d = f

ちゃんと理解してないので雑な説明 …

Page 29: Developing an Akka Edge6

Fork/Joinとは

タスクを分割していって、それらを並列に処理していくフレームワーク

Java7から導入された

タスクを細分化して…というのがActorの設計と似ているので、相性が良い

Page 30: Developing an Akka Edge6

fork-join-executorの設定

default-dispatcher{type=Dispatcherexecutor="fork-join-executor"throughput=10

fork-join-executor{parallelism-min=4parallelism-max=32parallelism-factor=4.0

}}

CPUのコア数×factor⇒並列実行するスレッド数

ただし、min < スレッド数 < max

Page 31: Developing an Akka Edge6

ThreadPoolExecutorとは

java.util.concurrent.ThreadPoolExecutorワーカスレッドを管理するクラス

タスクキューを持っていて

スレッドプールのスレッドを使ってタスクを実行

⇒終わったらスレッドプールにスレッドがもどる

というのを繰り返している

スレッド

Page 32: Developing an Akka Edge6

thread-pool-executorの設定

my-thread-dispatcher{type=Dispatcherexecutor="thread-pool-executor"thread-pool-executor{

core-pool-min = 4core-pool-max = 32core-pool-factor = 2.0

max-pool-min = 8max-pool-max = 84max-pool-factor = 3.0

keep-alive-time = 30ms

task-queue-type = “linked”}

}

core-poolとmax-poolそれぞれの設定がある

Page 33: Developing an Akka Edge6

corePoolとmaxPool新しいタスクが、キューに追加された時

①corePoolSize > 実行中のスレッド数

新しいスレッドが作成される

②corePoolSize < 実行中のスレッド数 < maxPoolSizeキューが一杯の時のみ新しいスレッドが作成される

③maxPoolSize == 実行中のスレッド数

キューが一杯ならタスクがrejectされる

Page 34: Developing an Akka Edge6

keep-alive-timecorePoolSize < 実行中のスレッド数 の時

タスクキューが空で暇なスレッドがあったら…

アイドル状態がkeep-alive-timeを超えるとスレッドが終了する

Page 35: Developing an Akka Edge6

task-queue-typeLinkedBlockingQueue(サイズ上限なし)

ArrayBlockingQueue(サイズ上限指定)

から選ぶ

※LinkedBlockingQueueを使うと、corePoolSizeの全てのスレッドがbusy状態の時

新しいタスクはキュー内にどんどんたまっていくので

corePoolSizeを超えるスレッドは作成されない※

大きなキューと小さなプールを使用すると、スループットが低下する恐れあり

(CPU使用率・context switchingのオーバーヘッドは最小化される)

Page 36: Developing an Akka Edge6

thread-pool-executorの設定

my-thread-dispatcher{type=Dispatcherexecutor="thread-pool-executor"thread-pool-executor{

core-pool-min = 4core-pool-max = 32core-pool-factor = 2.0

max-pool-min = 8max-pool-max = 84max-pool-factor = 3.0

keep-alive-time = 30ms}

}

Page 37: Developing an Akka Edge6

いろんなDispatcher

Page 38: Developing an Akka Edge6

いろんなDispatcherDispatcher

デフォルトで使っている

PinnedDispatcher

BalancingDispatcher

CallinThreadDispatcherakka.testkitに入ってるので、9章で登場するかも!?

Page 39: Developing an Akka Edge6

いろんなDispatcherDispatcher

デフォルトで使っている

PinnedDispatcher

BalancingDispatcher

CallinThreadDispatcherakka.testkitに入ってるので、9章で登場するかも!?

Page 40: Developing an Akka Edge6

PinnedDispatcherそれぞれのアクターに1スレッドずつ割り当てる。

⇒全てのアクターがスレッドをフルに使える

特に優先度が高いリソースを持っている時に使う

※このパターンを使いすぎないように!!※

Page 41: Developing an Akka Edge6

BalancingDispatcher1つのMailboxをシェアしている。

暇になったActorがメッセージを処理するので、負荷は公平

全て同じ型のActorと使う事を想定されている

(型が違っても、受け取れるメッセージが同じなら動きそう)

Page 42: Developing an Akka Edge6

6種のMailbox

Page 43: Developing an Akka Edge6

6種のMailboxUnboundedMailboxSingleConsumerOnlyUnboundedMailboxBoundedMailboxUnboundedPriorityMailboxBoundedPriorityMailboxDurable

Page 44: Developing an Akka Edge6

6種のMailboxUnboundedMailboxSingleConsumerOnlyUnboundedMailboxBoundedMailboxUnboundedPriorityMailboxBoundedPriorityMailboxDurable 1つのActorに1つのMailbox

(デフォルトはこれ)

他のMailboxが全部シェアしているのかは未確認です …

Page 45: Developing an Akka Edge6

6種のMailboxUnboundedMailboxSingleConsumerOnlyUnboundedMailboxBoundedMailboxUnboundedPriorityMailboxBoundedPriorityMailboxDurable Mailboxの容量が

有限 or 無限

Page 46: Developing an Akka Edge6

6種のMailbox容量が有限の時のパラメータ

mailbox-capacityMailboxの容量

mailbox-push-timeout-timeMailboxが一杯の時、空くのを待つ時間(?)

-1にすると無限

Page 47: Developing an Akka Edge6

6種のMailboxUnboundedMailboxSingleConsumerOnlyUnboundedMailboxBoundedMailboxUnboundedPriorityMailboxBoundedPriorityMailboxDurable Mailbox内のメッセージに

優先度付き

Page 48: Developing an Akka Edge6

6種のMailboxextendsして使う

Intで優先度を指定(0が優先度最高)

Page 49: Developing an Akka Edge6

6種のMailboxUnboundedMailboxSingleConsumerOnlyUnboundedMailboxBoundedMailboxUnboundedPriorityMailboxBoundedPriorityMailboxDurable Mailboxのメッセージを

永続化できる(ファイルシステム)

Page 50: Developing an Akka Edge6

ここまで長くなりましたが…

実際にDispatcherを使う

Page 51: Developing an Akka Edge6

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}

}

Page 52: Developing an Akka Edge6

Dispatcherを使う

②FutureのためにDispatcherを使う場合

implicit val executionContext = system.dispatchers.lookup(“my-dispatcher”)

Page 53: Developing an Akka Edge6

Mailboxを使う

myMailbox{mailbox-type = “BoundedMailbox”mailbox-capacity = 1000mailbox-push-timeout-time = 1

}

val myActor = system.actorOf(Props[MyActor].withMailbox(“myMailbox”)

Dispatcherの時と同様に、akka.actor.deployのActorの設定内に書いてもよい

Page 54: Developing an Akka Edge6

使用例Akka Concurrencyの

When to choose a dispatching method参照

Page 55: Developing an Akka Edge6

Low latency ⇒ PinnedDispatcherを使う

例:特定のActorに1スレッド丸ごと割り当てると…

スレッドが割り当てられるのを待たなくて良いので

メッセージをすぐ処理してくれる

Page 56: Developing an Akka Edge6

Bulkhead Pattern ⇒ Dispatcherを使う

例:IO処理と計算処理のActor達を別のDispatcherにすると…

計算処理Dispatcherのスレッド数を多くするなど

IO と 計算のどっちに比重を置くかチューニングができる

Page 57: Developing an Akka Edge6

cruch…ボリボリ噛む

なるべく全てのActorをbuzyにしたい時

Number cruching ⇒ BalangingDispatcherを使う

Page 58: Developing an Akka Edge6

IO処理が伴うので、Durableを使う時は他のアクターと分離させる

Message durability⇒ DurableとDispatcherを使う

Page 59: Developing an Akka Edge6

チューニングについてLet it crashの

Tuning Dispatchers in Akka Applications参照

Page 60: Developing an Akka Edge6

Dispatcherの設定

デフォルトの設定

default-dispatcher{type=Dispatcherexecutor="fork-join-executor"throughput=10

fork-join-executor{parallelism-min=4parallelism-max=32parallelism-factor=4.0

}}

なんやかんや言ってもデフォルト設定で良い場合が多い

Page 61: Developing an Akka Edge6

Typesafe Consoleでチェック

Dispatcher view でメッセージハンドリングのlatency、mailbox-sizeなどが見れる

(ちゃんと調べてませんが、現在は無料で使えないようです…)

Page 62: Developing an Akka Edge6

profilingしてheavy computationな部分を特定し

⇒RouterとBalancingDispatcherを使って外に出す

mailbox sizeが増え続けているならRouterを作った方がよい

デフォルトでもスレッド数の上限が決まっているので、

コア数を増やしても別のDispatcherを使わないと

futureがタイムアウトになったり、スループットが上がらない

Page 63: Developing an Akka Edge6

typeデフォルトの設定

default-dispatcher{type=Dispatcherexecutor="fork-join-executor"throughput=10

fork-join-executor{parallelism-min=4parallelism-max=32parallelism-factor=4.0

}}

← Dispatcherの種類

最優先処理がある場合PinnedDispatcher(よっぽど特別な場合だけ使用する)

負荷分散したい時はRouterとBalancingDispatcher

Page 64: Developing an Akka Edge6

executorデフォルトの設定

default-dispatcher{type=Dispatcherexecutor="fork-join-executor"throughput=10

fork-join-executor{parallelism-min=4parallelism-max=32parallelism-factor=4.0

}}

←executorの種類

fork-join-executorの方が良い(PinnedDispatcherはthread-pool-のみ)

Page 65: Developing an Akka Edge6

Let it crashの記事より、thread-poolからfork-joinにしたら1100%増になった

Throughput比較

task-queueへのアクセス/ロックが多い ⇒ context switchingが発生しやすい

Page 66: Developing an Akka Edge6

throughputデフォルトの設定

default-dispatcher{type=Dispatcherexecutor="fork-join-executor"throughput=10

fork-join-executor{parallelism-min=4parallelism-max=32parallelism-factor=4.0

}}

← throughput

Actor数≒スレッド数なら多め時間のかかるタスクが多いなら少なめ(頻繁に切り替わると時間がかかる)

デフォルト値から初めてチューニングすべし

Page 67: Developing an Akka Edge6

まとめ

・Actorにスレッドが割り当てられると、数個のメッセージを処理して

 スレッドプールに戻る

・パフォーマンスが悪い部分を別DispatcherとかRouterで切り出す

・Actorを小さく作れば、どのDispatcherに属させるか柔軟にチューニングできそう(チームの先輩談)