Mais conteúdo relacionado
Semelhante a Akkaの並行性 (20)
Akkaの並行性
- 2. Copyright © 2018 TIS Inc. All rights reserved.
TIS株式会社
前出 祐吾 @yugolf
最近の研究テーマ
オープン環境で⾼可⽤システムどうやって構築する?
翻訳した本
最近書いてる記事
ThinkIT:リアクティブシステムの使いどころ(仮)
2
⾃⼰紹介
- 3. Copyright © 2018 TIS Inc. All rights reserved.
Akkaを通じて
アクターモデルの並⾏性を知る
3
本⽇のお話
https://akka.io/
- 5. Copyright © 2018 TIS Inc. All rights reserved. 5
リアクティブシステムの4つの原則
• メッセージ駆動のアーキテクチャによりユーザーの要求に可能な限り迅速に
レスポンスする(即応性)システム
• ⾼負荷状況や問題が検出された時でも応答時間を⼀定⽔準に保ち(弾⼒
性)、部分的な障害が発⽣した時にもシステム全体を危険にさらすことなく
回復させる(耐障害性)
※リアクティブ宣言(https://www.reactivemanifesto.org/ja)より
- 6. Copyright © 2018 TIS Inc. All rights reserved. 6
⼿段となるメッセージ駆動
コンポーネント
コンポーネント
メッセージ駆動をアクターモデルで実現する
リアクティブシステムは⾮同期なメッセージパッシングによっ
てコンポーネント間の境界を確⽴する
- 8. Copyright © 2018 TIS Inc. All rights reserved. 8
アクターモデルとは
並⾏的に受信するメッセージに対する以下のふるまいを備える
• アクターを作る
• アクターにメッセージを送信する
• メッセージを受信したときの動作を指定する
トラディショナルモデルとの違い
トラディショナルモデル
アクターモデル
逐次実⾏が基本で部分的に並⾏処理を実装
本質的に並⾏
- 9. Copyright © 2018 TIS Inc. All rights reserved. 9
本質的に並⾏?
受付係 チケット販売員
Buy
Buy
メールボックス
Akkaを使うことでアクターのプログラミングに集中できる
• コンポーネント間のやり取りはメッセージで⾏う
• 関数の応答を待つ必要はなく並⾏に処理される
• アクターはメールボックスを持ち到着順に処理する
イベントA
イベントB
- 11. Copyright © 2018 TIS Inc. All rights reserved. 11
例:アクターモデルによるチケット販売サービス
• チケットの購⼊
• イベントの作成 チケット販売サービス
GoTicks.com
イベント管理者
お客さん
https://github.com/yugolf/akka-in-action-java/tree/master/chapter-up-and-running
Akka実践バイブル第1章より
ソースコード
- 12. Copyright © 2018 TIS Inc. All rights reserved. 12
クラス構成
ActorSystem
“go-ticks”
create
create
Actor
BoxOffice
Actor
TicketSeller
HTTP Route
RestApi
- 14. Copyright © 2018 TIS Inc. All rights reserved. 14
アクターシステムの⽣成
ActorSystem
“go-ticks”
Main
new
create
create
create
Actor
BoxOffice
Actor
TicketSeller
HTTP Route
RestApi
[Main] アクターシステムを⽣成する
final ActorSystem system = ActorSystem.create("go-ticks");
- 15. Copyright © 2018 TIS Inc. All rights reserved. 15
アクターの⽣成
[RestApi] アクターを⽣成する
ActorSystem
“go-ticks”
Main
new
create
create
create
Actor
BoxOffice
HTTP Route
RestApi
ActorRef boxOfficeActor =
system.actorOf(BoxOffice.props(timeout), "boxOfficeActor");
// propsの定義
public static Props props(Duration timeout) {
return Props.create(BoxOffice.class,
() -> new BoxOffice(timeout));
}
[BoxOffice] アクターのファクトリーメソッドを定義する
- 16. Copyright © 2018 TIS Inc. All rights reserved. 16
アクターシステム
https://doc.akka.io/docs/akka/2.5/general/supervision.html
アクターシステムに作成したアクターは、Userガーディアンの配下に⽣成され
ヒエラルキーを構成する
Actor
BoxOffice
Actor
TicketSeller
Actor
XXX
- 17. Copyright © 2018 TIS Inc. All rights reserved.
Interface
ITicketSeller
Interface
IBoxOffice
17
メッセージのやり取り1:イベントの作成
Reactive
Osaka
boxOffice
create
Add
Actor
BoxOffice
Actor
TicketSeller
BoxOfficeアクターがTicketSellerアクター(Reactive Osakaイベント)を
⽣成し、Addメッセージでイベントのチケットを追加する
• コンポーネント間のやり取りはメッセージで⾏う
• 関数の応答を待つ必要はなく並⾏に処理される
• アクターはメールボックスを持ち到着順に処理する
- 18. Copyright © 2018 TIS Inc. All rights reserved.
ticketSeller.tell(new TicketSeller.Add(newTickets), getSelf());
getContext().sender().tell(
new EventCreated(new Event(createEvent.getName(),
createEvent.getTickets())),
getSelf());
18
実装1/2 BoxOfficeからTicketSellerにAddメッセージを送信
[BoxOffice ] TicketSellerアクターの⽣成
String eventName = “Reactive Osaka”;
ActorRef ticketSeller = getContext()
.actorOf(TicketSeller.props(eventName), eventName);
BoxOffice TicketSeller
Add
[BoxOffice ] Addメッセージの送信
sender BoxOffece
EventCreated
送信元の処理と送信先の処理は⾮同期
- 19. Copyright © 2018 TIS Inc. All rights reserved. 19
実装2/2 BoxOfficeからTicketSellerにAddメッセージを送信
[TicketSeller] メッセージプロトコルの定義
[TicketSeller] メッセージ受信時のふるまい定義
interface ITicketSeller {
class Add extends AbstractMessage {
private final List<Ticket> tickets;
public Add(List<Ticket> tickets) {
this.tickets = Collections.unmodifiableList(new ArrayList<>(tickets));
}
public List<Ticket> getTickets() {
return tickets;
}
}
private final List<Ticket> tickets = new ArrayList<>();
private void add(Add add) {
log.debug(msg, add);
tickets.addAll(add.getTickets());
}
@Override
public Receive createReceive() {
return receiveBuilder()
.match(Add.class, this::add)
.build();
}
BoxOffice TicketSeller
Add
メッセージはイミュータブルに
受信するメッセージの型に対してふるまいを指定
- 20. Copyright © 2018 TIS Inc. All rights reserved. 20
おさらい:(再掲)アクターモデルとは
並⾏的に受信するメッセージに対する以下のふるまいを備える
• アクターを作る
• アクターにメッセージを送信する
• メッセージを受信したときの動作を指定する
トラディショナルモデルとの違い
トラディショナルモデル
アクターモデル
逐次実⾏が基本で部分的に並⾏処理を実装
本質的に並⾏
getContext().actorOf()
ticketSeller.tell()
receiveBuilder().match()
- 21. Copyright © 2018 TIS Inc. All rights reserved.
Interface
ITicketSeller
Interface
IBoxOffice
21
アクターの外からのメッセージ
Reactive
Osaka
boxOffice
create
Add
Actor
BoxOffice
Actor
TicketSeller
HTTP Route
RestApi
RestApi
CreateEvent
EventCreated
RestApiクラスはクライアントにレスポンスするためアクターからの
返信(イベントが作成できたか?)が必要
- 22. Copyright © 2018 TIS Inc. All rights reserved. 22
実装 RestApiからBoxOfficeにCreateEventメッセージを送信
[RestApi ] CreateEventメッセージを送信し応答を処理
CompletionStage<EventResponse> futureEventResponse =
ask(boxOfficeActor,
new CreateEvent(name, event.getTickets()),
timeout)
.thenApply(EventResponse.class::cast);
return onSuccess(() -> futureEventResponse, maybeEventResponse ->
{
log.debug(msg, maybeEventResponse);
...
});
RestApi BoxOffice
CreateEvent
EventCreated
CompletionStage:完了したときにアクションの実⾏または値
の計算を⾏う、⾮同期の可能性がある計算のステージです。
https://docs.oracle.com/javase/jp/8/docs/api/java/util/concurrent/CompletionStage.html
- 23. Copyright © 2018 TIS Inc. All rights reserved.
Interface
ITicketSeller
Interface
IBoxOffice
23
メッセージのやり取り2:チケットの購⼊
Reactive
Osaka
boxOffice
Tickets
Actor
BoxOffice
Actor
TicketSeller
HTTP Route
RestApi
RestApi
GetTickets
Buy
TicketSellerアクターはBuyメッセージを受信すると、状態(チケット)を
更新しTicketsメッセージをRestApiクラスに返信する
- 24. Copyright © 2018 TIS Inc. All rights reserved. 24
実装 BoxOfficeからTicketSellerへBuyメッセージを送信
[BoxOffice ] Buyメッセージの転送(返信先は送信元になる)
child.get().forward(new TicketSeller.Buy(getTickets.getTickets()),
getContext());
BoxOffice TicketSeller
Buy
RestApi
GetTickets
[TicketSeller] メッセージ受信時のふるまい
- 送信元へTicketsメッセージの返信
@Override
public Receive createReceive() {
return receiveBuilder()
.match(Buy.class, this::buy)
.build();
BoxOffice TicketSeller
Buy
BoxOffice
Tickets
private final List<Ticket> tickets = new ArrayList<>();
private void buy(Buy buy){
log.debug(msg, buy);
if (tickets.size() >= buy.getTickets()) {
List<Ticket> entries = tickets.subList(0, buy.getTickets());
getContext().sender().tell(new Tickets(event, entries), getSelf());
entries.clear();
} else {
getContext().sender().tell(new Tickets(event), getSelf());
}
}
アクターの持つ状態(tickets)を更新してい
るが、ロック制御を気にする必要はない
- 26. Copyright © 2018 TIS Inc. All rights reserved. 26
送信者が直接扱うのはActorではなくActorRef
Interface
ITicketSeller
Interface
IBoxOffice
Reactive
Osaka
boxOffice
create
Add
Actor
BoxOffice
Actor
TicketSeller
[BoxOffice ] TicketSellerアクターの⽣成
String eventName = “Reactive Osaka”;
ActorRef ticketSeller = getContext()
.actorOf(TicketSeller.props(eventName), eventName);
- 27. Copyright © 2018 TIS Inc. All rights reserved. 27
メッセージ送信の流れ
boxOffice
create
enqueue
thread
dequeue
Actor
MailBox
core
Dispatcher
Pinned Dispacher
CallingThreadDispatcher
Reactive
Osaka
Reactive
Osaka
ActorRef Actor
Dispatcher
1. ActorRefに対してメッセージを送信
2. ディスパッチャーはActorRefからメッセージを取得してメールボックスにエンキューする
3. ディスパッチャーはExecutionServiceに対してメールボックスをexecute
4. メールボックスはrunメソッドが起動されるとキューからメッセージを取り出しアクターに渡す
5. アクターのReceive処理が実⾏される
- 28. Copyright © 2018 TIS Inc. All rights reserved. 28
ディスパッチャー
Reactive
Osaka
box
Office
Actor
BoxOffice
Actor
TicketSeller
Dispatcherはアクターをスレッドプールに割り当てる
Scala
Matsuri
Thread
- 29. Copyright © 2018 TIS Inc. All rights reserved.
ブロッキング処理:デフォルトディスパッチャーの場合
29http://www.slideshare.net/ktoso/zen-of-akka#44
デフォルトのディスパッチャーでブロッキング処理を⾏うと
全体に影響を及ぼしてしまう
- 30. Copyright © 2018 TIS Inc. All rights reserved. 30http://www.slideshare.net/ktoso/zen-of-akka#44
ブロッキング処理:専⽤ディスパッチャーの場合
専⽤のディスパッチャを使ってブロッキング処理を隔離する
- 32. Copyright © 2018 TIS Inc. All rights reserved. 32
まとめ
• リアクティブシステムの原則の1つであるメッセージ駆動は
Akkaで実現できる
• アクターモデルは本質的に並⾏であり、スレッドを直接扱わず
に並⾏処理が実装できる
• ディスパッチャーなどによりスレッドモデルを設定できる
• 最⼤限のパフォーマンスを引き出すにはスレッドを意識した
チューニングが必要だが、実装とは切り離せる
第16章「パフォーマンスTips」にディスパッチャの
チューニング例を掲載