SlideShare a Scribd company logo
1 of 84
Download to read offline
Copyright © 2018 TIS Inc. All rights reserved.
JavaからAkkaハンズオン
JJUG Fall 2018
前出祐吾 @yugolf
JavaからAkkaハンズオンの準備⼿順
https://qiita.com/yugolf/items/701ba01ef283c868119a
Copyright © 2018 TIS Inc. All rights reserved.
TIS株式会社
 前出 祐吾 @yugolf
最近の研究テーマ
 オープン環境で⾼可⽤システムどうやって構築する?
翻訳した本
連載
 ThinkIT:メニーコア時代のパラダイム リアクティブシステムを知ろう
2
⾃⼰紹介
エンジニア積極採⽤中
Copyright © 2018 TIS Inc. All rights reserved. 3
本⽇のアジェンダ
1.Akkaとは
2.Akkaで実装してみる
‣ゴール
Akkaを使った実装の取っ掛かりを掴む
• Akkaでどう実装するのか?
• その後どう学んでいけばよいか?
Copyright © 2018 TIS Inc. All rights reserved. 4
教材
✦here
Copyright © 2018 TIS Inc. All rights reserved. 5
⽬次
https://www.shoeisha.co.jp/book/detail/9784798153278
第1章 Akkaの紹介
第2章 最⼩のAkkaアプリケーション
第3章 アクターによるテスト駆動開発
第4章 耐障害性
第5章 Future
第6章 Akkaによるはじめての分散アプリケーション
第7章 設定とロギングとデプロイ
第8章 アクターの構造パターン
第9章 メッセージのルーティング
第10章 メッセージチャネル
第11章 有限状態マシンとエージェント
第12章 ストリーミング
第13章 システム統合
第14章 クラスタリング
第15章 アクターの永続化
第16章 パフォーマンスTips
第17章 Akkaのこれから
付録 AkkaをJavaから使う
TODAY
• 第2章 最⼩のAkkaアプリケーション
• クローンとビルドとインターフェイスのテスト
• アプリケーションでのActorの探求
• クラウドへ
Copyright © 2018 TIS Inc. All rights reserved.
Akkaとは
6
第1章 Akkaの紹介
Copyright © 2018 TIS Inc. All rights reserved. 7
Akkaとは
並⾏・分散システムを構築するためのツールキット
• スケールアップ(並⾏)やスケールアウ
ト(分散)の実現によるアプリケーショ
ンの複雑化を抑⽌
• JavaとScalaのAPIを提供
Copyright © 2018 TIS Inc. All rights reserved. 8
単⼀のプログラミングモデルでスケールアップ・スケールアウト
アクターモデルはメッセージの送受信を抽象化することにより、
実装とスレッドの数やサーバーの台数に対する結合度を下げる
シングルスレッドで実⾏ 複数サーバーで実⾏
逐次処理 並⾏処理 分散処理
アクターモデル
マルチコアで実⾏
位置透過性
Copyright © 2018 TIS Inc. All rights reserved.
アクターモデル
9
第2章 最⼩のAkkaアプリケーション
Copyright © 2018 TIS Inc. All rights reserved. 10
アクターモデルとは
並⾏的に受信するメッセージに対する以下のふるまいを備える
• アクターを作る
• アクターにメッセージを送信する
• メッセージを受信したときの動作を指定する
トラディショナルモデルとの違い
トラディショナルモデル
アクターモデル
逐次実⾏が基本で部分的に並⾏処理を実装
本質的に並⾏
Copyright © 2018 TIS Inc. All rights reserved. 11
本質的に並⾏?
お客さん
チケット販売員
Buy
Buy
Buy
メールボックス
Akkaを使うことでアクターのプログラミングに集中できる
• コンポーネント間のやり取りはメッセージで⾏う
• 関数の応答を待つ必要はなく並⾏に処理される
• アクターはメールボックスを持ち到着順に処理する
Copyright © 2018 TIS Inc. All rights reserved. 12
もしあなたがErlangの世界のアクターだった場合
あなたは孤独な⼈間で、窓もない暗い部屋に座っていて、メール
ボックスにメッセージが届くのを待っている状態です。
そしてメッセージを受け取ると、それに対して特定の⽅法で反応し
ます:メッセージを受け取るときにお⾦を払い、誕⽣⽇カードには
「ありがとう(“Thank you”)」という⽂字で返事をし、理解出来な
い⽂字は無視するという具合です。
「すごいErlangゆかいに学ぼう!」より
https://www.ymotongpoo.com/works/lyse-ja/ja/01_introduction.html
Copyright © 2018 TIS Inc. All rights reserved.
Akkaのアクター
13
第2章 最⼩のAkkaアプリケーション
Copyright © 2018 TIS Inc. All rights reserved. 14
トラディショナルスタイルとAkkaを4つのケースで⽐較
Akkaとは/概要/従来型との違い/アクターのプログ
ラミングモデル/Akkaのアクター
1)データを保存して耐久性のあるものにしたい
2)インタラクティブな機能を実装したい
3)サービスを分離して疎結合にしたい
4)システム全体の障害を避けたい
Copyright © 2018 TIS Inc. All rights reserved. 15
1) データを耐久性のあるものにしたい
インメモリーに状態を持ち、ロック制御なしに書き換える
1万円引落し
1万円引落し
残⾼
1万円
ATM
モバイル
1万円引落し
1万円引落し
ロック ATM
モバイル
⼝座
残⾼
1万円
トラディショナル Akka
ボトルネック
Copyright © 2018 TIS Inc. All rights reserved. 16
1) データを耐久性のあるものにしたい
状態をイベントとして永続化しておき(Akka Persistence)、
これらを再⽣することで状態を復元できる
• 1万円引落
• 1万円引落
• 3万円預⼊
「スケールアウトしやすいようステートレスに」、
から「ステートフルでスケーラブルに」
イベントの永続化
イベントの再⽣
1万円引落し
1万円引落し
ATM
モバイル
⼝座
残⾼
1万円
イベントソーシング
Copyright © 2018 TIS Inc. All rights reserved. 17
2) インタラクティブな機能を作りたい
メッセージパッシングなので基本プッシュ
ポーリング
@Bob “こんにちは!”
Alice Bob
プッシュ
Alice Bob
チャットサーバー
トラディショナル Akka
Copyright © 2018 TIS Inc. All rights reserved.
チャットサーバー メンションサーバー
- 時間的疎結合:メッセージの応答を待たない
- 機能的疎結合:送信後どうなったか知らない
- 位置的疎結合:別サーバーにいてもいい
18
3) サービスを分離して疎結合にしたい
メッセージパッシングなので元々⾮同期で疎結合
• 密結合は複雑度をあげる
• 変更容易=技術的負債になりづらい、ほどよい疎結合
「メンション」がメッセー
ジを受信したときのふる
まいを定義するだけ
「メンション」のふるまい
が変わっても「会話」は影
響を受けない
チャット
エンキュー
デキュー
会話
メンションMeメンション
トラディショナル Akka
Copyright © 2018 TIS Inc. All rights reserved. 19
4) システム全体の障害を避けたい
アクターでエラーが発⽣したらスーパーバイザーへ
コーヒ1本
故障!!
システムをダウンさせないよう、
すべての障害を想定しCatch
⾃販機でコーヒーを買う
try {
vendingMachine.buy()
} catch () {
// ⾃販機の故障など
// 障害が発⽣したときの処理
}
障害制御はスーパーバイザーに任せる
Dave
⾃販機
スーパーバイザー
トラディショナル Akka
- 障害制御においても疎結合
(⾃動販売機の故障はコーヒーを買った⼈では
なく⾃動販売機の管理者が対処)
Copyright © 2018 TIS Inc. All rights reserved. 20
スーパーバイザーヒエラルキー
https://doc.akka.io/docs/akka/2.5/general/supervision.html
Akkaは適切な単位で障害制御を⾏うため、スーパーバイザーヒエラルキーを持つ
Copyright © 2018 TIS Inc. All rights reserved. 21
1)データを耐久性のあるものにしたい
DB  インメモリーで状態を持ちイベントを永続化
2)インタラクティブな機能を実装したい
ポーリング  メッセージパッシング
3)サービスを分離して疎結合にしたい
キュー  アクター間は疎結合
4)システム全体の障害を避けたい
全障害シナリオをキャッチ  コンポーネント間で影響なし
トラディショナルスタイルとAkkaを4つのケースで⽐較してみた
Copyright © 2018 TIS Inc. All rights reserved.
最小のAkkaアプリケーション
22
•クローンとビルドとインターフェイスのテスト
•アプリケーションでのActorの探求
•クラウドへ
Copyright © 2018 TIS Inc. All rights reserved. 23
クローンとビルド
• github.com からサンプルプロジェクトをクローン
$git	clone	https://github.com/yugolf/akka-in-action-java.git
$cd	akka-in-action-java/chapter-up-and-running/	
$mvn	compile	exec:exec
https://github.com/yugolf/akka-in-action-java/tree/master/chapter-up-and-running
• ビルドとアプリケーションの起動
Slf4jLogger:	Slf4jLogger	started	
Main:	start	actor	system:	go-ticks	
Main:	Server	online	at	http://0.0.0.0:5000	
Main:	Press	RETURN	to	stop...
※Mavenがインストールされていない場合はmvnwを使⽤してください。
例) ./mvnw compile exec:exec
https://github.com/takari/maven-wrapper
※事前準備でクローン済の⼈はgit pull で最新を取得してください。
Copyright © 2018 TIS Inc. All rights reserved. 24
プロジェクトの構成
プロジェクトの構造
リソース
ソースコード
テストコード
ビルド成果物 Mavenのビルドファイル
https://www.jetbrains.com/idea/download/
Copyright © 2018 TIS Inc. All rights reserved. 25
構築するアプリケーション
• イベント⼀覧の参照
• チケットの購⼊
• イベントの作成
• イベントのキャンセル
チケット販売サービス
GoTicks.com
イベント管理者
お客さん
Copyright © 2018 TIS Inc. All rights reserved. 26
Web API確認のための準備
まずは、動かしてみましょう!
HTTPリクエストのツールをインストールしてアプリを起動
• HTTPリクエスト送信ツールのインストール
• HTTPie または Advanced REST client
- CLI: HTTPie (https://httpie.org/)
- GUI: Advanced REST client(Chrome Extensions)
https://chrome.google.com/webstore/detail/advanced-rest-
client/hgmloofddffdnphfgcellkdfbfbjeloo
$brew	install	httpie
Copyright © 2018 TIS Inc. All rights reserved. 27
HTTPieでリクエスト送信
• CLI: HTTPie
$http	POST	localhost:5000/events/JJUG/	tickets:=3	
HTTP/1.1	201	Created	
Content-Length:	27	
Content-Type:	application/json	
Date:	Sun,	02	Dec	2018	06:42:52	GMT	
Server:	GoTicks.com	REST	API	
{	
				"name":	"JJUG",	
				"tickets":	3	
}
Copyright © 2018 TIS Inc. All rights reserved. 28
REST clientでリクエスト送信
• GUI: Advanced REST client(Chrome Extensions)
(1) (2)
(3)
(4)
(8)
http://localhost:5000/events/JJUG
(5)
(6)
(7)
{"tickets":3}
Copyright © 2018 TIS Inc. All rights reserved. 29
APIのエンドポイント
HTTPieコマンド
• イベント作成
• チケット購⼊
• イベント⼀覧取得
• イベント取得
• イベントキャンセル
$http	POST	localhost:5000/events/JJUG/	tickets:=3
$http	GET	localhost:5000/events
$http	POST	localhost:5000/events/JJUG/tickets	tickets:=2
$http	DELETE	localhost:5000/events/JJUG/
機能 HTTPメソッド パス JSON
イベント作成 POST /events/<イベント名>/ {"tickets":<枚数>}
チケット購⼊ POST /events/<イベント名>/tickets/ {"tickets":<枚数>}
イベント⼀覧 GET /events/
イベント取得 GET /events/<イベント名>/
イベントキャンセル DELETE /events/<イベント名>/
$http	GET	localhost:5000/events/JJUG/
Copyright © 2018 TIS Inc. All rights reserved. 30
>イベント⼀覧の取得
>「JJUG」を2枚購⼊
>イベント⼀覧の取得
>「JJUG」を8枚購⼊
>「JJUG」を2枚購⼊
>チケット10枚の「JJUG」イベントを作成
>チケット20枚の「ScalaMatsuri」イベントを作成
>「ScalaMatsuri」をキャンセル
>イベント⼀覧の取得
チケット販売サービスを使ってみる
イベント管理者
お客さん
Copyright © 2018 TIS Inc. All rights reserved.
最小のAkkaアプリケーション
31
•クローンとビルドとインターフェイスのテスト
•アプリケーションでのActorの探求
•クラウドへ
Copyright © 2018 TIS Inc. All rights reserved. 32
ハンズオン⽤のブランチを取得
ワークショップ⽤ブランチの取得
$ git	checkout	handson
Copyright © 2018 TIS Inc. All rights reserved.
ActorSystem	
“go-ticks”
33
クラス構成
Main
HTTP	Server
run
new
create
create
create
Actor	
BoxOffice
Actor	
TicketSeller
HTTP	Route	
RestApi
Copyright © 2018 TIS Inc. All rights reserved.
Interface	
ITicketSeller
Interface	
IBoxOffice
34
アクターの関係
JJUG
Scala	
Matsuri
boxOffice
create
Add/Buy/Cancel/…
Actor	
BoxOffice
Actor	
TicketSeller
Copyright © 2018 TIS Inc. All rights reserved.
Exercise 0. アクターシステムの生成
35
演習0.アクターシステムの⽣成
Copyright © 2018 TIS Inc. All rights reserved.
ActorSystem	
“go-ticks”
36
アクターシステムの⽣成
アクターシステムの⽣成
Main
HTTP	Server
HTTP	Route	
RestApi
Actor	
BoxOffice
Actor	
TicketSeller
run
new
create
create
create
Copyright © 2018 TIS Inc. All rights reserved. 37
「go-ticks」 ActorSystemを⽣成する
0.0.[Main] ActorSystemの⽣成
アプリケーションの実⾏
final ActorSystem system = ActorSystem.create("go-ticks");
$ mvn compile exec:exec
...
Slf4jLogger:	Slf4jLogger	started	
Main:	start	actor	system:	go-ticks	
Main:	Server	online	at	http://0.0.0.0:5000	
Main:	Press	RETURN	to	stop...
※Mavenがインストールされていない場合はmvnwを使⽤してください。
例) ./mvnw compile exec:exec
https://github.com/takari/maven-wrapper
Copyright © 2018 TIS Inc. All rights reserved.
Exercise 1. イベントの作成
38
演習1.イベントの作成
Copyright © 2018 TIS Inc. All rights reserved. 39
HTTP	Route	
RestApi
Actor	
BoxOffice
Actor	
TicketSeller
CreateEvent
create
EventCreated
EventExists
POST	
/events/JJUG
Created	201	
BadRequest	400
Add
イベント作成時のメッセージの流れ
Copyright © 2018 TIS Inc. All rights reserved. 40
イベント作成時のメッセージの流れ:実装箇所
実装するところ
Actorの⽣成とメッセージ送信(Add/ EventCreated)
HTTP	Route	
RestApi
Actor	
BoxOffice
Actor	
TicketSeller
CreateEvent
create
AddEventCreated
EventExists
POST	
/events/JJUG
Created	201	
BadRequest	400
Copyright © 2018 TIS Inc. All rights reserved. 41
実装: アクターの⽣成・定義とメッセージ送信
演習1:TicketSellerアクターの⽣成、Addメッセージ
の送信、EventCreatedメッセージの返信
• TicketSellerアクターの⽣成
1.1.[TicketSeller] アクターのファクトリーメソッドを定義
1.2.[BoxOffice ] TicketSellerアクターの⽣成
• BoxOfficeアクターからTicketSellerアクターへAddメッセージを送信
1.3.[TicketSeller] メッセージプロトコルの定義
1.4.[TicketSeller] メッセージ受信時のふるまい定義
1.5.[BoxOffice ] Addメッセージの送信
• BoxOfficeからRestApiへEventCreatedメッセージを返信
1.6.[BoxOffice ] EventCreatedメッセージの返信
Copyright © 2018 TIS Inc. All rights reserved. 42
テストによる実⾏結果の確認
RestApiTest#testCreateEventの実⾏
$mvn test -Dtest=RestApiTest#testCreateEvent
...
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.goticks.RestApiTest
Slf4jLogger: Slf4jLogger started
Slf4jLogger: Slf4jLogger started
RestApi: ---------- POST /events/RHCP/ {"tickets":3} ----------
BoxOffice: 📩 IBoxOffice.CreateEvent[name=RHCP,tickets=3]
TicketSeller: 📩 ITicketSeller.Add[tickets=[ITicketSeller.Ticket[id=1],
ITicketSeller.Ticket[id=2], ITicketSeller.Ticket[id=3]]]
RestApi: 📩 IBoxOffice.EventCreated[event=IBoxOffice.Event[name=RHCP,tickets=3]]
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.634 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
...
※Windowsだと「📩 」が「?」で表⽰されます。
Copyright © 2018 TIS Inc. All rights reserved. 43
実装1/3 TicketSellerアクターの⽣成
1.1.[TicketSeller] アクターのファクトリーメソッドを定義
1.2.[BoxOffice ] TicketSellerアクターの⽣成
public static Props props(String event) {
return Props.create(TicketSeller.class, () -> new TicketSeller(event));
}
public class BoxOffice extends AbstractActor {
...
private ActorRef createTicketSeller(String name) {
return getContext().actorOf(TicketSeller.props(name), name);
}
BoxOffice TicketSeller
create
Copyright © 2018 TIS Inc. All rights reserved. 44
実装2/3 BoxOfficeからTicketSellerにAddメッセージを送信
1.3.[TicketSeller] メッセージプロトコルの定義
1.4.[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
Copyright © 2018 TIS Inc. All rights reserved. 45
実装3/3 BoxOfficeからTicketSellerにAddメッセージを送信
1.5.[BoxOffice ] Addメッセージの送信
1.6.[BoxOffice ] EventCreatedメッセージの返信
private void createEvent(CreateEvent createEvent) {
log.debug(msg, createEvent);
Optional<ActorRef> child = getContext().findChild(createEvent.getName());
if (child.isPresent()) {
getContext().sender().tell(new EventExists(), self());
} else {
ActorRef ticketSeller = createTicketSeller(createEvent.getName());
List<TicketSeller.Ticket> newTickets =
IntStream.rangeClosed(1, createEvent.getTickets())
.mapToObj(ticketId -> (new TicketSeller.Ticket(ticketId)))
.collect(Collectors.toList());
ticketSeller.tell(new TicketSeller.Add(newTickets), getSelf());
getContext().sender().tell(new EventCreated(new Event(createEvent.getName(),
createEvent.getTickets())), getSelf());
}
}
BoxOffice TicketSeller
Add
RestApi BoxOffice
EventCreated
Copyright © 2018 TIS Inc. All rights reserved. 46
Exercise1のポイント
• Actorの⽣成
• メッセージの送信
• メッセージ受信時のふるまい
• メッセージプロトコルの定義
getContext().actorOf(TicketSeller.props(name), name);
eventTickets.tell(new TicketSeller.Add(newTickets), getSelf());
public static class Add{
private final List<Ticket> tickets;
public Add(List<Ticket> tickets) {
this.tickets = Collections.unmodifiableList(new ArrayList<>(tickets));
}
public List<Ticket> getTickets() {
return tickets;
}
}
@Override
public Receive createReceive() {
return receiveBuilder()
.match(Add.class, this::add)
.build();
public static Props props(String event) {
return Props.create(TicketSeller.class, () -> new TicketSeller(event));
}
Copyright © 2018 TIS Inc. All rights reserved.
Exercise 2. チケットの購入
演習2.チケットの購⼊
Copyright © 2018 TIS Inc. All rights reserved. 48
チケット購⼊時のメッセージの流れ
チケットを購⼊するフロー
GetTicketsPOST	
/events/JJUG/tickets
Created	201	
NotFound	404
HTTP	Route	
RestApi
Actor	
BoxOffice
Actor	
TicketSeller
Buy
Tickets
Copyright © 2018 TIS Inc. All rights reserved. 49
GetTickets
Buy
Tickets
POST	
/events/JJUG/tickets
Created	201	
NotFound	404
HTTP	Route	
RestApi
Actor	
BoxOffice
Actor	
TicketSeller
実装するところ
メッセージ送信(Buy/ Tickets)
チケット購⼊時のメッセージの流れ:実装箇所
Copyright © 2018 TIS Inc. All rights reserved. 50
実装: Buyメッセージの送信とTicketsメッセージの返信
• BoxOfficeからTicketSellerへBuyメッセージを送信
2.1.[TicketSeller] メッセージプロトコルの定義
2.2.[TicketSeller] メッセージ受信時のふるまい
- 送信元へTicketsメッセージの返信
2.3.[BoxOffice ] Buyメッセージの転送
※TicketSellerからのメッセージの返信先を⾃⾝(BoxOffice)ではなく、
RestApi(TicketSellerいメッセージを送った⼈)にしたい
2.4.[BoxOffice ] 空のTicketsメッセージを返信
Copyright © 2018 TIS Inc. All rights reserved. 51
チケット購⼊の動作確認
$mvn test -Dtest=RestApiTest#testBuy
...
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.goticks.RestApiTest
Slf4jLogger: Slf4jLogger started
Slf4jLogger: Slf4jLogger started
RestApi: ---------- POST /events/RHCP/ {"tickets":3} ----------
BoxOffice: 📩 IBoxOffice.CreateEvent[name=RHCP,tickets=3]
TicketSeller: 📩 ITicketSeller.Add[tickets=[ITicketSeller.Ticket[id=1],
ITicketSeller.Ticket[id=2], ITicketSeller.Ticket[id=3]]]
RestApi: 📩 IBoxOffice.EventCreated[event=IBoxOffice.Event[name=RHCP,tickets=3]]
RestApi: ---------- POST /events/RHCP/tickets/ {"tickets":2} ----------
BoxOffice: 📩 IBoxOffice.GetTickets[event=RHCP,tickets=2]
TicketSeller: 📩 ITicketSeller.Buy[tickets=2]
RestApi: 📩 ITicketSeller.Tickets[event=RHCP,entries=[ITicketSeller.Ticket[id=1],
ITicketSeller.Ticket[id=2]]]
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.577 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
...
テストによる実⾏結果の確認
RestApiTest#testBuyの実⾏
Copyright © 2018 TIS Inc. All rights reserved. 52
実装1/2 BoxOfficeからTicketSellerへBuyメッセージを送信
2.1.[TicketSeller] メッセージプロトコルの定義
2.2.[TicketSeller] メッセージ受信時のふるまい
- 送信元へTicketsメッセージの返信
interface ITicketSeller {
class Buy extends AbstractMessage {
private final int tickets;
public Buy(int tickets) {
this.tickets = tickets;
}
public int getTickets() {
return 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());
}
}
Copyright © 2018 TIS Inc. All rights reserved. 53
実装2/2 BoxOfficeからTicketSellerへBuyメッセージを送信
2.3.[BoxOffice ] Buyメッセージの転送
2.4.[BoxOffice ] 空のTicketsメッセージを返信
if (child.isPresent())
child.get().forward(new TicketSeller.Buy(getTickets.getTickets()), getContext());
else
getContext().sender().tell(new TicketSeller.Tickets(getTickets.getEvent()), getSelf());
BoxOffice TicketSeller
Buy
BoxOffice
Tickets
Copyright © 2018 TIS Inc. All rights reserved. 54
Exercise2のポイント
• メッセージの転送
child.get().forward(new TicketSeller.Buy(getTickets.getTickets()), getContext());
※⾃⾝ではなく、⾃⾝へメッセージを送ってきた⼈に直接返信してほしいときは
forwardを使う
Copyright © 2018 TIS Inc. All rights reserved.
Exercise 3. イベント一覧の取得
55
演習3.イベント⼀覧の取得
Copyright © 2018 TIS Inc. All rights reserved. 56
イベント取得時のメッセージの流れ
イベント⼀覧を取得するフロー
GetEventGET	
/events/JJUG
OK	200	Events
HTTP	Route	
RestApi
Actor	
BoxOffice
Actor	
TicketSeller
empty
GetEvent
Event
Copyright © 2018 TIS Inc. All rights reserved. 57
イベント⼀覧取得時のメッセージの流れ
イベント⼀覧を取得するフロー
GetEventsGET	
/events/
OK	200	Events
HTTP	Route	
RestApi
Actor	
BoxOffice
Actor	
TicketSeller
GetEvent
empty
GetEvent
Event
Events
Copyright © 2018 TIS Inc. All rights reserved. 58
GetEvents
GetEvent
Event
GET	
/events/
OK	200	Events
GetEvent
empty
Events
HTTP	Route	
RestApi
Actor	
BoxOffice
Actor	
TicketSeller
イベント⼀覧取得時のメッセージの流れ:実装箇所
Copyright © 2018 TIS Inc. All rights reserved. 59
実装: GetEventメッセージの送信とEventsメッセージの返信
• TicketSellerにGetEventメッセージを送信する(準備)
3.1.[TicketSeller] メッセージプロトコルの定義
3.2.[TicketSeller] メッセージ受信時のふるまい
- Eventメッセージの返信
• BoxOfficeから⾃⾝にGetEventメッセージを送信
3.3.[BoxOffice ] ⾃分宛てにGetEventメッセージを送信
• BoxOfficeにGetEventメッセージ受信時のふるまいを定義
3.4.[BoxOffice ] ⼦アクターが存在する場合:
- ⼦アクター(TicketSeller)へGetEventメッセージを転送
3.5.[BoxOffice ] ⼦アクターが存在しない場合:
- Optional.empty()メッセージを返信
• BoxOfficeからEventsメッセージの返信
3.6.[BoxOffice ] Eventsメッセージを送信元へ返信
Copyright © 2018 TIS Inc. All rights reserved. 60
テストによる実⾏結果の確認
チケット⼀覧取得の動作確認
$mvn test -Dtest=RestApiTest#testGetEvents
...
-------------------------------------------------------	
	T	E	S	T	S	
-------------------------------------------------------	
Running	com.goticks.RestApiTest	
Slf4jLogger:	Slf4jLogger	started	
Slf4jLogger:	Slf4jLogger	started	
RestApi:	----------	POST	/events/RHCP/	{"tickets":3}	----------	
BoxOffice:					📩 	IBoxOffice.CreateEvent[name=RHCP,tickets=3]	
TicketSeller:		📩 	ITicketSeller.Add[tickets=[ITicketSeller.Ticket[id=1],	
ITicketSeller.Ticket[id=2],	ITicketSeller.Ticket[id=3]]]	
RestApi:							📩 	IBoxOffice.EventCreated[event=IBoxOffice.Event[name=RHCP,tickets=3]]	
RestApi:	----------	GET	/events/	----------	
BoxOffice:					📩 	IBoxOffice.GetEvents[]	
BoxOffice:					📩 	IBoxOffice.GetEvent[name=RHCP]	
TicketSeller:		📩 	ITicketSeller.GetEvent[]	
RestApi:							📩 	IBoxOffice.Events[events=[IBoxOffice.Event[name=RHCP,tickets=3]]]	
Tests	run:	1,	Failures:	0,	Errors:	0,	Skipped:	0,	Time	elapsed:	5.186	sec	
Results	:	
Tests	run:	1,	Failures:	0,	Errors:	0,	Skipped:	0
RestApiTest#testGetEventsの実⾏
Copyright © 2018 TIS Inc. All rights reserved. 61
実装1/4 TicketSellerにGetEventメッセージを送信する(準備)
3.1.[TicketSeller] メッセージプロトコルの定義
3.2.[TicketSeller] メッセージ受信時のふるまい
- Eventメッセージの返信
@Override
public Receive createReceive() {
return receiveBuilder()
.match(GetEvent.class, this::getEvent)
.build();
}
class GetEvent extends AbstractMessage {
}
BoxOffice TicketSeller
Event
private void getEvent(GetEvent getEvent) {
log.debug(msg, getEvent);
sender().tell(Optional.of(new BoxOffice.Event(event, tickets.size())), self());
}
GetEvent
Copyright © 2018 TIS Inc. All rights reserved. 62
実装2/4 BoxOfficeから⾃⾝にGetEventメッセージを送信
GetEventメッセージを⾃⾝(self)に送信する
3.3.[BoxOffice ] GetEventメッセージを⾃分宛てに送信
// 子アクター(TicketSeller)に ask した結果のリストを作成
List<CompletableFuture<Optional<Event>>> children = new ArrayList<>();
getContext().getChildren().forEach(child ->
children.add(ask(getSelf(), new GetEvent(child.path().name()), timeout)
.thenApply(event -> (Optional<Event>) event)
.toCompletableFuture()));
BoxOffice
GetEvent
Copyright © 2018 TIS Inc. All rights reserved. 63
実装3/4 BoxOfficeにGetEventメッセージ受信時のふるまいを定義
3.4.[BoxOffice ] ⼦アクターが存在する:
- ⼦アクターへGetEventメッセージを転送
3.5.[BoxOffice ] ⼦アクターが存在しない:
- Optional.empty()を返信
private void getEvent(GetEvent getEvent) {
log.debug(msg, getEvent);
Optional<ActorRef> child = getContext().findChild(getEvent.getName());
if (child.isPresent())
child.get().forward(new TicketSeller.GetEvent(), getContext());
else
getContext().sender().tell(Optional.empty(), getSelf());
}
BoxOffice TicketSeller
GetEvent
Optional.empty()
Copyright © 2018 TIS Inc. All rights reserved. 64
実装4/4 BoxOfficeからEventsメッセージを返信
pipeを使って、処理完了時にFuture内の値(Events)
を送信元に返信する
3.6.[BoxOffice ] Eventsメッセージを送信元へ返信
private void getEvents(GetEvents getEvents) {
// 子アクター(TicketSeller)に ask した結果のリストを作成
List<CompletableFuture<Optional<Event>>> children = new ArrayList<>();
getContext().getChildren().forEach(child ->
children.add(ask(getSelf(), new GetEvent(child.path().name()), timeout)
.thenApply(event -> (Optional<Event>) event)
.toCompletableFuture()));
// List<CompletableFuture<Optional<Event>>> の children を
// CompletionStage<Events> に変換
// Events は List<Event> を持つ
CompletionStage<Events> futureEvents = CompletableFuture
.allOf(children.toArray(new CompletableFuture[0]))
.thenApply(ignored -> {
List<Event> events = children.stream()
.map(CompletableFuture::join)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
return new Events(events);
});
pipe(futureEvents, getContext().dispatcher()).to(sender());
}
RestApi BoxOffice
Events
Copyright © 2018 TIS Inc. All rights reserved. 65
Exercise3のポイント
応答が必要なメッセージ、⾃⾝へのメッセージ送信
レスポンスが必要な場合のメッセージ送信
⾃分宛てのメッセージ送信
ask(getSelf(), new GetEvent(child.path().name()), timeout)
.thenApply(event -> (Optional<Event>) event);
pipe(futureEvents, getContext().dispatcher()).to(sender());
ask(getSelf(), new GetEvent(child.path().name()), timeout)
※レスポンスがほしいときはaskを使う(使いすぎ注意)
※pipeでCompletableFuture完了時結果を返す
Copyright © 2018 TIS Inc. All rights reserved.
Exercise 4. イベントのキャンセル
66
演習4.イベントのキャンセル
Copyright © 2018 TIS Inc. All rights reserved. 67
イベントキャンセルのメッセージの流れ
イベントをキャンセルするフロー
CancelEvent
Cancel
Event
DELETE	
/events/JJUG
OK	200	
NotFound	404
empty
PoisonPill
HTTP	Route	
RestApi
Actor	
BoxOffice
Actor	
TicketSeller
Copyright © 2018 TIS Inc. All rights reserved. 68
CancelEvent
Cancel
Event
DELETE	
/events/JJUG
empty
PoisonPill
HTTP	Route	
RestApi
Actor	
BoxOffice
Actor	
TicketSeller
イベントキャンセルのメッセージの流れ:実装箇所
実装するところ
メッセージ送信(Cancel/ Event)、アクターの停⽌
OK	200	
NotFound	404
Copyright © 2018 TIS Inc. All rights reserved. 69
実装: Cancelメッセージの送信とTicketSellerアクターの停⽌
演習4:Cancelメッセージの送信とTicketSellerアク
ターの停⽌
BoxOfficeからTicketSellerへCancelメッセージを送信
4.1.[TicketSeller] メッセージプロトコルの定義
4.2.[TicketSeller] メッセージ受信時のふるまい
Eventメッセージの返信
⾃分宛てにPoisonPillメッセージの送信 ※毒薬を飲んで⾃殺
4.3.[BoxOffice ] ⼦アクターが存在する場合:
- ⼦アクター(TicketSeller)へCancelメッセージを転送
4.4.[BoxOffice ] ⼦アクターが存在しない場合:
- Optional.empty()メッセージを返信
Copyright © 2018 TIS Inc. All rights reserved. 70
テストによる実⾏結果の確認
$mvn	test	-Dtest=RestApiTest#testCancel	
...	
-------------------------------------------------------	
	T	E	S	T	S	
-------------------------------------------------------	
Running	com.goticks.RestApiTest	
Slf4jLogger:	Slf4jLogger	started	
Slf4jLogger:	Slf4jLogger	started	
RestApi:	----------	POST	/events/RHCP/	{"tickets":3}	----------	
BoxOffice:					📩 	IBoxOffice.CreateEvent[name=RHCP,tickets=3]	
TicketSeller:		📩 	ITicketSeller.Add[tickets=[ITicketSeller.Ticket[id=1],	
ITicketSeller.Ticket[id=2],	ITicketSeller.Ticket[id=3]]]	
RestApi:							📩 	IBoxOffice.EventCreated[event=IBoxOffice.Event[name=RHCP,tickets=3]]	
RestApi:	----------	DELETE	/events/RHCP/	----------	
BoxOffice:					📩 	IBoxOffice.CancelEvent[name=RHCP]	
TicketSeller:		📩 	ITicketSeller.Cancel[]	
RestApi:							📩 	Optional[IBoxOffice.Event[name=RHCP,tickets=3]]	
Tests	run:	1,	Failures:	0,	Errors:	0,	Skipped:	0,	Time	elapsed:	5.679	sec	
Results	:	
Tests	run:	1,	Failures:	0,	Errors:	0,	Skipped:	0	
RestApiTest#testCancelの実⾏
Copyright © 2018 TIS Inc. All rights reserved. 71
実装1/2 BoxOfficeからTicketSellerへCancelメッセージの送信
4.1.[TicketSeller] メッセージプロトコルの定義
4.2.[TicketSeller] メッセージ受信時のふるまい
- Eventメッセージの返信
- ⾃⾝にPoisonPillメッセージを送信する(PoisonPillを受信するとアクターは停⽌する)
class Cancel extends AbstractMessage {
}
@Override
public Receive createReceive() {
return receiveBuilder()
.match(Cancel.class, this::cancel)
.build();
}
private void cancel(Cancel cancel){
log.debug(msg, cancel);
sender().tell(Optional.of(new BoxOffice.Event(event, tickets.size())), self());
self().tell(PoisonPill.getInstance(), self());
}
BoxOffice TicketSeller
Event
Cancel PoisonPill
Copyright © 2018 TIS Inc. All rights reserved. 72
実装2/2 BoxOfficeからTicketSellerへCancelメッセージの送信
4.3.[BoxOffice ] ⼦アクターが存在する場合:
- ⼦アクター(TicketSeller)へCancelメッセージを転送
4.4.[BoxOffice ] ⼦アクターが存在しない場合:
- Optional.empty()メッセージを返信
private void cancelEvent(CancelEvent cancelEvent) {
log.debug(msg, cancelEvent);
Optional<ActorRef> child = getContext().findChild(cancelEvent.getName());
if (child.isPresent())
child.get().forward(new TicketSeller.Cancel(), getContext());
else
getContext().sender().tell(Optional.empty(), getSelf());
}
BoxOffice TicketSeller
Cancel
Optional.empty()
Copyright © 2018 TIS Inc. All rights reserved. 73
Exercise4のポイント
応答が必要なメッセージ、⾃⾝へのメッセージ送信
アクターはPoisonPillメッセージを受信すると停⽌する
self().tell(PoisonPill.getInstance(), self());
※PoisonPillはActorを殺すための毒薬
Copyright © 2018 TIS Inc. All rights reserved.
Exercise 5. APIに仕立てる(解説)
74
Copyright © 2018 TIS Inc. All rights reserved. 75
APIのエンドポイント(再掲)
HTTPieコマンド
• イベント作成
• チケット購⼊
• イベント⼀覧取得
• イベント取得
• イベントキャンセル
$http	POST	localhost:5000/events/JJUG/	tickets:=3
$http	GET	localhost:5000/events
$http	POST	localhost:5000/events/JJUG/tickets	tickets:=2
$http	DELETE	localhost:5000/events/JJUG/
機能 HTTPメソッド パス JSON
イベント作成 POST /events/<イベント名>/ {"tickets":<枚数>}
チケット購⼊ POST /events/<イベント名>/tickets/ {"tickets":<枚数>}
イベント⼀覧 GET /events/
イベント取得 GET /events/<イベント名>/
イベントキャンセル DELETE /events/<イベント名>/
$http	GET	localhost:5000/events/JJUG/
Copyright © 2018 TIS Inc. All rights reserved. 76
エンドポイントの作成(Akka HTTP)
RestAPI#createRoute
import akka.http.javadsl.server.Route;
public Route createRoute() {
return route(
pathPrefix("events", () -> route(
getEvents(),
pathPrefix(segment(), (String name) -> route(
getEvent(name),
createEvent(name),
cancelEvent(name)
)),
pathPrefix(segment().slash(segment("tickets")), (String event) -> route(
requestTickets(event)
))
))
);
}
• AkkaHTTPが提供するDSLを使ってHTTPリクエストの制御⽅法を定義
Copyright © 2018 TIS Inc. All rights reserved. 77
RestApi#getEvents
private Route getEvents() {
// [Get all events] GET /events/
return get(() ->
pathEndOrSingleSlash(() -> {
log.debug("---------- GET /events/ ----------");
CompletionStage<Events> events =
ask(boxOfficeActor, new GetEvents(), timeout)
.thenApply((Events.class::cast));
return onSuccess(() -> events, maybeEvent -> {
log.debug(msg, maybeEvent);
return completeOK(maybeEvent, Jackson.marshaller());
});
})
);
}
エンドポイントの作成(Akka HTTP)
Copyright © 2018 TIS Inc. All rights reserved.
最小のAkkaアプリケーション
78
•クローンとビルドとインターフェイスのテスト
•アプリケーションでのActorの探求
•クラウドへ
Copyright © 2018 TIS Inc. All rights reserved. 79
クラウドへ1/2
Heroku上にアプリケーションを乗せる
• Mainクラスに標準⼊⼒を待ち受けサーバーをダウンさせる実装があるため
Heroku上で動かすにはこの部分を削除
$cd ..
$heroku login
$heroku create go-ticks
Creating ⬢ go-ticks... done
https://go-ticks.herokuapp.com/ | https://git.heroku.com/go-ticks.git
Heroku CLIのインストール
$brew	install	heroku
System.in.read();
log.info("presses return...");
binding
.thenCompose(ServerBinding::unbind)
.thenAccept(unbound -> system.terminate());
Copyright © 2018 TIS Inc. All rights reserved. 80
クラウドへ2/2
Herokuにソースコードをプッシュ
$git subtree push --prefix chapter-up-and-running heroku master
....
remote: -----> Compressing...
remote: Done: 73M
remote: -----> Launching...
remote: Released v3
remote: https://go-ticks.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/go-ticks.git
* [new branch] 0f4dac16e9abbdbb694502f21d314281c6affd66 -> master
$ http POST go-ticks.herokuapp.com/events/JJUG tickets:=250
$ http POST go-ticks.herokuapp.com/events/JJUG/tickets tickets:=4
Heroku上のアプリケーションにアクセス
※chapter-up-and-running配下のプロジェクトをプッシュする
Copyright © 2018 TIS Inc. All rights reserved.
さいごに
81
Copyright © 2018 TIS Inc. All rights reserved. 82
さいごに
やったこと
• Akkaを使って⼩さなWebサービスを構築
残された課題
• アプリケーションを再起動するとデータは消える
• スケールアップもスケールアウトもしない
• テストを実装していない
• 1台のサーバーがダウンするとシステム全体がダウンする
Akkaのエコシステムで解決できるのでぜひチャレンジしてください。
https://akka.io/docs/
Akka
Actors Akka
Http Akka
Cluster Cluster
Sharing
Distributed
Data
Akka
Persistence
Alpakka
Copyright © 2018 TIS Inc. All rights reserved.
チャレンジのお供に
83
• メニーコア時代のパラダイム リアクティブシステムを知ろう(ThinkIT)
サンプルコードはScalaで書かれ
いますが、付録でJavaのAPIも
紹介しています
本⽇のサンプルアプリケーションのScala版はこちら
https://github.com/akka-ja/akka-in-action/tree/master/chapter-up-and-running
THANK YOU
We are hiring!!
いっしょにチャレンジしませんか?

More Related Content

What's hot

【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しようUnity Technologies Japan K.K.
 
Twitterのsnowflakeについて
TwitterのsnowflakeについてTwitterのsnowflakeについて
Twitterのsnowflakeについてmoai kids
 
AngularとSpring Bootで作るSPA + RESTful Web Serviceアプリケーション
AngularとSpring Bootで作るSPA + RESTful Web ServiceアプリケーションAngularとSpring Bootで作るSPA + RESTful Web Serviceアプリケーション
AngularとSpring Bootで作るSPA + RESTful Web Serviceアプリケーションssuser070fa9
 
Demystifying Identities for Azure Kubernetes Service
Demystifying Identities for Azure Kubernetes ServiceDemystifying Identities for Azure Kubernetes Service
Demystifying Identities for Azure Kubernetes ServiceToru Makabe
 
Amazon EKS によるスマホゲームのバックエンド運用事例
Amazon EKS によるスマホゲームのバックエンド運用事例Amazon EKS によるスマホゲームのバックエンド運用事例
Amazon EKS によるスマホゲームのバックエンド運用事例gree_tech
 
LogbackからLog4j 2への移行によるアプリケーションのスループット改善 ( JJUG CCC 2021 Fall )
LogbackからLog4j 2への移行によるアプリケーションのスループット改善 ( JJUG CCC 2021 Fall ) LogbackからLog4j 2への移行によるアプリケーションのスループット改善 ( JJUG CCC 2021 Fall )
LogbackからLog4j 2への移行によるアプリケーションのスループット改善 ( JJUG CCC 2021 Fall ) Hironobu Isoda
 
Spring 歴約1年初心者の Test 奮闘記
Spring 歴約1年初心者の Test 奮闘記Spring 歴約1年初心者の Test 奮闘記
Spring 歴約1年初心者の Test 奮闘記chishizu naito
 
これからSpringを使う開発者が知っておくべきこと
これからSpringを使う開発者が知っておくべきことこれからSpringを使う開発者が知っておくべきこと
これからSpringを使う開発者が知っておくべきこと土岐 孝平
 
JIRA / Confluence の 必須プラグインはこれだ
JIRA / Confluence の必須プラグインはこれだJIRA / Confluence の必須プラグインはこれだ
JIRA / Confluence の 必須プラグインはこれだNarichika Kajihara
 
とにかく分かりづらいTwelve-Factor Appの解説を試みる
とにかく分かりづらいTwelve-Factor Appの解説を試みるとにかく分かりづらいTwelve-Factor Appの解説を試みる
とにかく分かりづらいTwelve-Factor Appの解説を試みるMasatoshi Tada
 
DeNAのゲームを支えるプラットフォーム Sakasho #denatechcon
DeNAのゲームを支えるプラットフォーム Sakasho #denatechconDeNAのゲームを支えるプラットフォーム Sakasho #denatechcon
DeNAのゲームを支えるプラットフォーム Sakasho #denatechconDeNA
 
Keycloakの実際・翻訳プロジェクト紹介
Keycloakの実際・翻訳プロジェクト紹介Keycloakの実際・翻訳プロジェクト紹介
Keycloakの実際・翻訳プロジェクト紹介Hiroyuki Wada
 
大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~
大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~
大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~infinite_loop
 
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション土岐 孝平
 
Ganglia のUIにGrafanaを追加する話
Ganglia のUIにGrafanaを追加する話Ganglia のUIにGrafanaを追加する話
Ganglia のUIにGrafanaを追加する話KLab Inc. / Tech
 
ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計Yoshinori Matsunobu
 
Nuxt.jsとExpressでSPA×SSR×API Aggregationを実現した話
Nuxt.jsとExpressでSPA×SSR×API Aggregationを実現した話Nuxt.jsとExpressでSPA×SSR×API Aggregationを実現した話
Nuxt.jsとExpressでSPA×SSR×API Aggregationを実現した話Recruit Lifestyle Co., Ltd.
 
ゲームの仕様書を書こうまとめ
ゲームの仕様書を書こうまとめゲームの仕様書を書こうまとめ
ゲームの仕様書を書こうまとめSugimoto Chizuru
 
NTTデータ流Infrastructure as Code~ 大規模プロジェクトを通して考え抜いた基盤自動化の新たな姿~(NTTデータ テクノロジーカンフ...
NTTデータ流Infrastructure as Code~ 大規模プロジェクトを通して考え抜いた基盤自動化の新たな姿~(NTTデータ テクノロジーカンフ...NTTデータ流Infrastructure as Code~ 大規模プロジェクトを通して考え抜いた基盤自動化の新たな姿~(NTTデータ テクノロジーカンフ...
NTTデータ流Infrastructure as Code~ 大規模プロジェクトを通して考え抜いた基盤自動化の新たな姿~(NTTデータ テクノロジーカンフ...NTT DATA Technology & Innovation
 
PFNのオンプレ計算機クラスタの取り組み_第55回情報科学若手の会
PFNのオンプレ計算機クラスタの取り組み_第55回情報科学若手の会PFNのオンプレ計算機クラスタの取り組み_第55回情報科学若手の会
PFNのオンプレ計算機クラスタの取り組み_第55回情報科学若手の会Preferred Networks
 

What's hot (20)

【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
 
Twitterのsnowflakeについて
TwitterのsnowflakeについてTwitterのsnowflakeについて
Twitterのsnowflakeについて
 
AngularとSpring Bootで作るSPA + RESTful Web Serviceアプリケーション
AngularとSpring Bootで作るSPA + RESTful Web ServiceアプリケーションAngularとSpring Bootで作るSPA + RESTful Web Serviceアプリケーション
AngularとSpring Bootで作るSPA + RESTful Web Serviceアプリケーション
 
Demystifying Identities for Azure Kubernetes Service
Demystifying Identities for Azure Kubernetes ServiceDemystifying Identities for Azure Kubernetes Service
Demystifying Identities for Azure Kubernetes Service
 
Amazon EKS によるスマホゲームのバックエンド運用事例
Amazon EKS によるスマホゲームのバックエンド運用事例Amazon EKS によるスマホゲームのバックエンド運用事例
Amazon EKS によるスマホゲームのバックエンド運用事例
 
LogbackからLog4j 2への移行によるアプリケーションのスループット改善 ( JJUG CCC 2021 Fall )
LogbackからLog4j 2への移行によるアプリケーションのスループット改善 ( JJUG CCC 2021 Fall ) LogbackからLog4j 2への移行によるアプリケーションのスループット改善 ( JJUG CCC 2021 Fall )
LogbackからLog4j 2への移行によるアプリケーションのスループット改善 ( JJUG CCC 2021 Fall )
 
Spring 歴約1年初心者の Test 奮闘記
Spring 歴約1年初心者の Test 奮闘記Spring 歴約1年初心者の Test 奮闘記
Spring 歴約1年初心者の Test 奮闘記
 
これからSpringを使う開発者が知っておくべきこと
これからSpringを使う開発者が知っておくべきことこれからSpringを使う開発者が知っておくべきこと
これからSpringを使う開発者が知っておくべきこと
 
JIRA / Confluence の 必須プラグインはこれだ
JIRA / Confluence の必須プラグインはこれだJIRA / Confluence の必須プラグインはこれだ
JIRA / Confluence の 必須プラグインはこれだ
 
とにかく分かりづらいTwelve-Factor Appの解説を試みる
とにかく分かりづらいTwelve-Factor Appの解説を試みるとにかく分かりづらいTwelve-Factor Appの解説を試みる
とにかく分かりづらいTwelve-Factor Appの解説を試みる
 
DeNAのゲームを支えるプラットフォーム Sakasho #denatechcon
DeNAのゲームを支えるプラットフォーム Sakasho #denatechconDeNAのゲームを支えるプラットフォーム Sakasho #denatechcon
DeNAのゲームを支えるプラットフォーム Sakasho #denatechcon
 
Keycloakの実際・翻訳プロジェクト紹介
Keycloakの実際・翻訳プロジェクト紹介Keycloakの実際・翻訳プロジェクト紹介
Keycloakの実際・翻訳プロジェクト紹介
 
大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~
大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~
大規模ソーシャルゲームを支える技術~PHP+MySQLを使った高負荷対策~
 
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション
 
Ganglia のUIにGrafanaを追加する話
Ganglia のUIにGrafanaを追加する話Ganglia のUIにGrafanaを追加する話
Ganglia のUIにGrafanaを追加する話
 
ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計
 
Nuxt.jsとExpressでSPA×SSR×API Aggregationを実現した話
Nuxt.jsとExpressでSPA×SSR×API Aggregationを実現した話Nuxt.jsとExpressでSPA×SSR×API Aggregationを実現した話
Nuxt.jsとExpressでSPA×SSR×API Aggregationを実現した話
 
ゲームの仕様書を書こうまとめ
ゲームの仕様書を書こうまとめゲームの仕様書を書こうまとめ
ゲームの仕様書を書こうまとめ
 
NTTデータ流Infrastructure as Code~ 大規模プロジェクトを通して考え抜いた基盤自動化の新たな姿~(NTTデータ テクノロジーカンフ...
NTTデータ流Infrastructure as Code~ 大規模プロジェクトを通して考え抜いた基盤自動化の新たな姿~(NTTデータ テクノロジーカンフ...NTTデータ流Infrastructure as Code~ 大規模プロジェクトを通して考え抜いた基盤自動化の新たな姿~(NTTデータ テクノロジーカンフ...
NTTデータ流Infrastructure as Code~ 大規模プロジェクトを通して考え抜いた基盤自動化の新たな姿~(NTTデータ テクノロジーカンフ...
 
PFNのオンプレ計算機クラスタの取り組み_第55回情報科学若手の会
PFNのオンプレ計算機クラスタの取り組み_第55回情報科学若手の会PFNのオンプレ計算機クラスタの取り組み_第55回情報科学若手の会
PFNのオンプレ計算機クラスタの取り組み_第55回情報科学若手の会
 

Similar to JavaからAkkaハンズオン

LoRaWANとAzure IoT Hub接続ハンズオン
LoRaWANとAzure IoT Hub接続ハンズオンLoRaWANとAzure IoT Hub接続ハンズオン
LoRaWANとAzure IoT Hub接続ハンズオンTomokazu Kizawa
 
Terraform with Bitbucket pipeline
Terraform with Bitbucket pipelineTerraform with Bitbucket pipeline
Terraform with Bitbucket pipelineMasatomo Ito
 
第5回 デジタルガジェット祭り! スマートスピーカー特集(4)
第5回 デジタルガジェット祭り! スマートスピーカー特集(4)第5回 デジタルガジェット祭り! スマートスピーカー特集(4)
第5回 デジタルガジェット祭り! スマートスピーカー特集(4)aitc_jp
 
DLモデル開発中の雑務が嫌で支援プラットフォームを作った話
DLモデル開発中の雑務が嫌で支援プラットフォームを作った話DLモデル開発中の雑務が嫌で支援プラットフォームを作った話
DLモデル開発中の雑務が嫌で支援プラットフォームを作った話Kamonohashi
 
テレビ版GYAO!アプリへのOAuth2.0 Device Flowの実装
テレビ版GYAO!アプリへのOAuth2.0 Device Flowの実装テレビ版GYAO!アプリへのOAuth2.0 Device Flowの実装
テレビ版GYAO!アプリへのOAuth2.0 Device Flowの実装Hiromitsu Homma
 
Spring I/O 2018 報告 RESTDocs RAML, Cloud Contract
Spring I/O 2018 報告 RESTDocs RAML, Cloud ContractSpring I/O 2018 報告 RESTDocs RAML, Cloud Contract
Spring I/O 2018 報告 RESTDocs RAML, Cloud ContractTakuya Iwatsuka
 
Spring Boot × Vue.jsでSPAを作る
Spring Boot × Vue.jsでSPAを作るSpring Boot × Vue.jsでSPAを作る
Spring Boot × Vue.jsでSPAを作るGo Miyasaka
 
Jazug-8th: Azure AKS & FIWARE & Robot
Jazug-8th: Azure AKS & FIWARE & RobotJazug-8th: Azure AKS & FIWARE & Robot
Jazug-8th: Azure AKS & FIWARE & RobotNobuyuki Matsui
 
AITCオープンラボ 2018年5月度(2)
AITCオープンラボ 2018年5月度(2)AITCオープンラボ 2018年5月度(2)
AITCオープンラボ 2018年5月度(2)aitc_jp
 
ソフトウェアジャパン2018 ITフォーラムセッション(3)
ソフトウェアジャパン2018 ITフォーラムセッション(3)ソフトウェアジャパン2018 ITフォーラムセッション(3)
ソフトウェアジャパン2018 ITフォーラムセッション(3)aitc_jp
 
JTF2018 FIWARE x robot x IoT
JTF2018 FIWARE x robot x IoTJTF2018 FIWARE x robot x IoT
JTF2018 FIWARE x robot x IoTNobuyuki Matsui
 
技術選択とアーキテクトの役割
技術選択とアーキテクトの役割技術選択とアーキテクトの役割
技術選択とアーキテクトの役割Toru Yamaguchi
 

Similar to JavaからAkkaハンズオン (20)

LoRaWANとAzure IoT Hub接続ハンズオン
LoRaWANとAzure IoT Hub接続ハンズオンLoRaWANとAzure IoT Hub接続ハンズオン
LoRaWANとAzure IoT Hub接続ハンズオン
 
React vtecx20171025
React vtecx20171025React vtecx20171025
React vtecx20171025
 
Terraform with Bitbucket pipeline
Terraform with Bitbucket pipelineTerraform with Bitbucket pipeline
Terraform with Bitbucket pipeline
 
React vtecx20171129
React vtecx20171129React vtecx20171129
React vtecx20171129
 
YJTC18 A-1 大規模サーバの戦略
YJTC18 A-1 大規模サーバの戦略YJTC18 A-1 大規模サーバの戦略
YJTC18 A-1 大規模サーバの戦略
 
第5回 デジタルガジェット祭り! スマートスピーカー特集(4)
第5回 デジタルガジェット祭り! スマートスピーカー特集(4)第5回 デジタルガジェット祭り! スマートスピーカー特集(4)
第5回 デジタルガジェット祭り! スマートスピーカー特集(4)
 
DLモデル開発中の雑務が嫌で支援プラットフォームを作った話
DLモデル開発中の雑務が嫌で支援プラットフォームを作った話DLモデル開発中の雑務が嫌で支援プラットフォームを作った話
DLモデル開発中の雑務が嫌で支援プラットフォームを作った話
 
テレビ版GYAO!アプリへのOAuth2.0 Device Flowの実装
テレビ版GYAO!アプリへのOAuth2.0 Device Flowの実装テレビ版GYAO!アプリへのOAuth2.0 Device Flowの実装
テレビ版GYAO!アプリへのOAuth2.0 Device Flowの実装
 
【初心者向け】API を使ってクラウドの管理を自動化しよう
【初心者向け】API を使ってクラウドの管理を自動化しよう【初心者向け】API を使ってクラウドの管理を自動化しよう
【初心者向け】API を使ってクラウドの管理を自動化しよう
 
Spring I/O 2018 報告会
Spring I/O 2018 報告会Spring I/O 2018 報告会
Spring I/O 2018 報告会
 
Spring I/O 2018 報告 RESTDocs RAML, Cloud Contract
Spring I/O 2018 報告 RESTDocs RAML, Cloud ContractSpring I/O 2018 報告 RESTDocs RAML, Cloud Contract
Spring I/O 2018 報告 RESTDocs RAML, Cloud Contract
 
Spring Boot × Vue.jsでSPAを作る
Spring Boot × Vue.jsでSPAを作るSpring Boot × Vue.jsでSPAを作る
Spring Boot × Vue.jsでSPAを作る
 
JSUG 2018 BTC
JSUG 2018 BTCJSUG 2018 BTC
JSUG 2018 BTC
 
React vtecx20170822
React vtecx20170822React vtecx20170822
React vtecx20170822
 
Jazug-8th: Azure AKS & FIWARE & Robot
Jazug-8th: Azure AKS & FIWARE & RobotJazug-8th: Azure AKS & FIWARE & Robot
Jazug-8th: Azure AKS & FIWARE & Robot
 
Go + Pulsar WebSocket APIの利用事例 #pulsarjp
Go + Pulsar WebSocket APIの利用事例 #pulsarjpGo + Pulsar WebSocket APIの利用事例 #pulsarjp
Go + Pulsar WebSocket APIの利用事例 #pulsarjp
 
AITCオープンラボ 2018年5月度(2)
AITCオープンラボ 2018年5月度(2)AITCオープンラボ 2018年5月度(2)
AITCオープンラボ 2018年5月度(2)
 
ソフトウェアジャパン2018 ITフォーラムセッション(3)
ソフトウェアジャパン2018 ITフォーラムセッション(3)ソフトウェアジャパン2018 ITフォーラムセッション(3)
ソフトウェアジャパン2018 ITフォーラムセッション(3)
 
JTF2018 FIWARE x robot x IoT
JTF2018 FIWARE x robot x IoTJTF2018 FIWARE x robot x IoT
JTF2018 FIWARE x robot x IoT
 
技術選択とアーキテクトの役割
技術選択とアーキテクトの役割技術選択とアーキテクトの役割
技術選択とアーキテクトの役割
 

More from TIS Inc.

AWSマネージドサービスとOSSによるミッションクリティカルなシステムの実現
AWSマネージドサービスとOSSによるミッションクリティカルなシステムの実現AWSマネージドサービスとOSSによるミッションクリティカルなシステムの実現
AWSマネージドサービスとOSSによるミッションクリティカルなシステムの実現TIS Inc.
 
Reactive Systems that focus on High Availability with Lerna
Reactive Systems that focus on High Availability with LernaReactive Systems that focus on High Availability with Lerna
Reactive Systems that focus on High Availability with LernaTIS Inc.
 
Starting Reactive Systems with Lerna #reactive_shinjuku
Starting Reactive Systems with Lerna #reactive_shinjukuStarting Reactive Systems with Lerna #reactive_shinjuku
Starting Reactive Systems with Lerna #reactive_shinjukuTIS Inc.
 
可用性を突き詰めたリアクティブシステム
可用性を突き詰めたリアクティブシステム可用性を突き詰めたリアクティブシステム
可用性を突き詰めたリアクティブシステムTIS Inc.
 
EventStormingワークショップ 〜かつてない図書館をモデリングしてみよう〜
EventStormingワークショップ 〜かつてない図書館をモデリングしてみよう〜EventStormingワークショップ 〜かつてない図書館をモデリングしてみよう〜
EventStormingワークショップ 〜かつてない図書館をモデリングしてみよう〜TIS Inc.
 
Akkaの並行性
Akkaの並行性Akkaの並行性
Akkaの並行性TIS Inc.
 
リアクティブシステムとAkka
リアクティブシステムとAkkaリアクティブシステムとAkka
リアクティブシステムとAkkaTIS Inc.
 
Akka in Action workshop #ScalaMatsuri 2018
Akka in Action workshop #ScalaMatsuri 2018Akka in Action workshop #ScalaMatsuri 2018
Akka in Action workshop #ScalaMatsuri 2018TIS Inc.
 
Preparing for distributed system failures using akka #ScalaMatsuri
Preparing for distributed system failures using akka #ScalaMatsuriPreparing for distributed system failures using akka #ScalaMatsuri
Preparing for distributed system failures using akka #ScalaMatsuriTIS Inc.
 
Akkaで実現するステートフルでスケーラブルなアーキテクチャ
Akkaで実現するステートフルでスケーラブルなアーキテクチャAkkaで実現するステートフルでスケーラブルなアーキテクチャ
Akkaで実現するステートフルでスケーラブルなアーキテクチャTIS Inc.
 
akka-doc-ja
akka-doc-jaakka-doc-ja
akka-doc-jaTIS Inc.
 
10分で分かるリアクティブシステム
10分で分かるリアクティブシステム10分で分かるリアクティブシステム
10分で分かるリアクティブシステムTIS Inc.
 
Typesafe Reactive Platformで作るReactive System入門
Typesafe Reactive Platformで作るReactive System入門Typesafe Reactive Platformで作るReactive System入門
Typesafe Reactive Platformで作るReactive System入門TIS Inc.
 
Typesafe Reactive Platformで作るReactive System
Typesafe Reactive Platformで作るReactive SystemTypesafe Reactive Platformで作るReactive System
Typesafe Reactive Platformで作るReactive SystemTIS Inc.
 
Effective Akka読書会2
Effective Akka読書会2Effective Akka読書会2
Effective Akka読書会2TIS Inc.
 
再帰で脱Javaライク
再帰で脱Javaライク再帰で脱Javaライク
再帰で脱JavaライクTIS Inc.
 
Scalable Generator: Using Scala in SIer Business (ScalaMatsuri)
Scalable Generator: Using Scala in SIer Business (ScalaMatsuri)Scalable Generator: Using Scala in SIer Business (ScalaMatsuri)
Scalable Generator: Using Scala in SIer Business (ScalaMatsuri)TIS Inc.
 
甲賀流Jenkins活用術
甲賀流Jenkins活用術甲賀流Jenkins活用術
甲賀流Jenkins活用術TIS Inc.
 

More from TIS Inc. (18)

AWSマネージドサービスとOSSによるミッションクリティカルなシステムの実現
AWSマネージドサービスとOSSによるミッションクリティカルなシステムの実現AWSマネージドサービスとOSSによるミッションクリティカルなシステムの実現
AWSマネージドサービスとOSSによるミッションクリティカルなシステムの実現
 
Reactive Systems that focus on High Availability with Lerna
Reactive Systems that focus on High Availability with LernaReactive Systems that focus on High Availability with Lerna
Reactive Systems that focus on High Availability with Lerna
 
Starting Reactive Systems with Lerna #reactive_shinjuku
Starting Reactive Systems with Lerna #reactive_shinjukuStarting Reactive Systems with Lerna #reactive_shinjuku
Starting Reactive Systems with Lerna #reactive_shinjuku
 
可用性を突き詰めたリアクティブシステム
可用性を突き詰めたリアクティブシステム可用性を突き詰めたリアクティブシステム
可用性を突き詰めたリアクティブシステム
 
EventStormingワークショップ 〜かつてない図書館をモデリングしてみよう〜
EventStormingワークショップ 〜かつてない図書館をモデリングしてみよう〜EventStormingワークショップ 〜かつてない図書館をモデリングしてみよう〜
EventStormingワークショップ 〜かつてない図書館をモデリングしてみよう〜
 
Akkaの並行性
Akkaの並行性Akkaの並行性
Akkaの並行性
 
リアクティブシステムとAkka
リアクティブシステムとAkkaリアクティブシステムとAkka
リアクティブシステムとAkka
 
Akka in Action workshop #ScalaMatsuri 2018
Akka in Action workshop #ScalaMatsuri 2018Akka in Action workshop #ScalaMatsuri 2018
Akka in Action workshop #ScalaMatsuri 2018
 
Preparing for distributed system failures using akka #ScalaMatsuri
Preparing for distributed system failures using akka #ScalaMatsuriPreparing for distributed system failures using akka #ScalaMatsuri
Preparing for distributed system failures using akka #ScalaMatsuri
 
Akkaで実現するステートフルでスケーラブルなアーキテクチャ
Akkaで実現するステートフルでスケーラブルなアーキテクチャAkkaで実現するステートフルでスケーラブルなアーキテクチャ
Akkaで実現するステートフルでスケーラブルなアーキテクチャ
 
akka-doc-ja
akka-doc-jaakka-doc-ja
akka-doc-ja
 
10分で分かるリアクティブシステム
10分で分かるリアクティブシステム10分で分かるリアクティブシステム
10分で分かるリアクティブシステム
 
Typesafe Reactive Platformで作るReactive System入門
Typesafe Reactive Platformで作るReactive System入門Typesafe Reactive Platformで作るReactive System入門
Typesafe Reactive Platformで作るReactive System入門
 
Typesafe Reactive Platformで作るReactive System
Typesafe Reactive Platformで作るReactive SystemTypesafe Reactive Platformで作るReactive System
Typesafe Reactive Platformで作るReactive System
 
Effective Akka読書会2
Effective Akka読書会2Effective Akka読書会2
Effective Akka読書会2
 
再帰で脱Javaライク
再帰で脱Javaライク再帰で脱Javaライク
再帰で脱Javaライク
 
Scalable Generator: Using Scala in SIer Business (ScalaMatsuri)
Scalable Generator: Using Scala in SIer Business (ScalaMatsuri)Scalable Generator: Using Scala in SIer Business (ScalaMatsuri)
Scalable Generator: Using Scala in SIer Business (ScalaMatsuri)
 
甲賀流Jenkins活用術
甲賀流Jenkins活用術甲賀流Jenkins活用術
甲賀流Jenkins活用術
 

Recently uploaded

論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A surveyToru Tamaki
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものですiPride Co., Ltd.
 
Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By DanielPostman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Danieldanielhu54
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...Toru Tamaki
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムsugiuralab
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Yuma Ohgami
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdftaisei2219
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNetToru Tamaki
 
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略Ryo Sasaki
 

Recently uploaded (9)

論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものです
 
Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By DanielPostman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Daniel
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システム
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdf
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet
 
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
 

JavaからAkkaハンズオン

  • 1. Copyright © 2018 TIS Inc. All rights reserved. JavaからAkkaハンズオン JJUG Fall 2018 前出祐吾 @yugolf JavaからAkkaハンズオンの準備⼿順 https://qiita.com/yugolf/items/701ba01ef283c868119a
  • 2. Copyright © 2018 TIS Inc. All rights reserved. TIS株式会社  前出 祐吾 @yugolf 最近の研究テーマ  オープン環境で⾼可⽤システムどうやって構築する? 翻訳した本 連載  ThinkIT:メニーコア時代のパラダイム リアクティブシステムを知ろう 2 ⾃⼰紹介 エンジニア積極採⽤中
  • 3. Copyright © 2018 TIS Inc. All rights reserved. 3 本⽇のアジェンダ 1.Akkaとは 2.Akkaで実装してみる ‣ゴール Akkaを使った実装の取っ掛かりを掴む • Akkaでどう実装するのか? • その後どう学んでいけばよいか?
  • 4. Copyright © 2018 TIS Inc. All rights reserved. 4 教材 ✦here
  • 5. Copyright © 2018 TIS Inc. All rights reserved. 5 ⽬次 https://www.shoeisha.co.jp/book/detail/9784798153278 第1章 Akkaの紹介 第2章 最⼩のAkkaアプリケーション 第3章 アクターによるテスト駆動開発 第4章 耐障害性 第5章 Future 第6章 Akkaによるはじめての分散アプリケーション 第7章 設定とロギングとデプロイ 第8章 アクターの構造パターン 第9章 メッセージのルーティング 第10章 メッセージチャネル 第11章 有限状態マシンとエージェント 第12章 ストリーミング 第13章 システム統合 第14章 クラスタリング 第15章 アクターの永続化 第16章 パフォーマンスTips 第17章 Akkaのこれから 付録 AkkaをJavaから使う TODAY • 第2章 最⼩のAkkaアプリケーション • クローンとビルドとインターフェイスのテスト • アプリケーションでのActorの探求 • クラウドへ
  • 6. Copyright © 2018 TIS Inc. All rights reserved. Akkaとは 6 第1章 Akkaの紹介
  • 7. Copyright © 2018 TIS Inc. All rights reserved. 7 Akkaとは 並⾏・分散システムを構築するためのツールキット • スケールアップ(並⾏)やスケールアウ ト(分散)の実現によるアプリケーショ ンの複雑化を抑⽌ • JavaとScalaのAPIを提供
  • 8. Copyright © 2018 TIS Inc. All rights reserved. 8 単⼀のプログラミングモデルでスケールアップ・スケールアウト アクターモデルはメッセージの送受信を抽象化することにより、 実装とスレッドの数やサーバーの台数に対する結合度を下げる シングルスレッドで実⾏ 複数サーバーで実⾏ 逐次処理 並⾏処理 分散処理 アクターモデル マルチコアで実⾏ 位置透過性
  • 9. Copyright © 2018 TIS Inc. All rights reserved. アクターモデル 9 第2章 最⼩のAkkaアプリケーション
  • 10. Copyright © 2018 TIS Inc. All rights reserved. 10 アクターモデルとは 並⾏的に受信するメッセージに対する以下のふるまいを備える • アクターを作る • アクターにメッセージを送信する • メッセージを受信したときの動作を指定する トラディショナルモデルとの違い トラディショナルモデル アクターモデル 逐次実⾏が基本で部分的に並⾏処理を実装 本質的に並⾏
  • 11. Copyright © 2018 TIS Inc. All rights reserved. 11 本質的に並⾏? お客さん チケット販売員 Buy Buy Buy メールボックス Akkaを使うことでアクターのプログラミングに集中できる • コンポーネント間のやり取りはメッセージで⾏う • 関数の応答を待つ必要はなく並⾏に処理される • アクターはメールボックスを持ち到着順に処理する
  • 12. Copyright © 2018 TIS Inc. All rights reserved. 12 もしあなたがErlangの世界のアクターだった場合 あなたは孤独な⼈間で、窓もない暗い部屋に座っていて、メール ボックスにメッセージが届くのを待っている状態です。 そしてメッセージを受け取ると、それに対して特定の⽅法で反応し ます:メッセージを受け取るときにお⾦を払い、誕⽣⽇カードには 「ありがとう(“Thank you”)」という⽂字で返事をし、理解出来な い⽂字は無視するという具合です。 「すごいErlangゆかいに学ぼう!」より https://www.ymotongpoo.com/works/lyse-ja/ja/01_introduction.html
  • 13. Copyright © 2018 TIS Inc. All rights reserved. Akkaのアクター 13 第2章 最⼩のAkkaアプリケーション
  • 14. Copyright © 2018 TIS Inc. All rights reserved. 14 トラディショナルスタイルとAkkaを4つのケースで⽐較 Akkaとは/概要/従来型との違い/アクターのプログ ラミングモデル/Akkaのアクター 1)データを保存して耐久性のあるものにしたい 2)インタラクティブな機能を実装したい 3)サービスを分離して疎結合にしたい 4)システム全体の障害を避けたい
  • 15. Copyright © 2018 TIS Inc. All rights reserved. 15 1) データを耐久性のあるものにしたい インメモリーに状態を持ち、ロック制御なしに書き換える 1万円引落し 1万円引落し 残⾼ 1万円 ATM モバイル 1万円引落し 1万円引落し ロック ATM モバイル ⼝座 残⾼ 1万円 トラディショナル Akka ボトルネック
  • 16. Copyright © 2018 TIS Inc. All rights reserved. 16 1) データを耐久性のあるものにしたい 状態をイベントとして永続化しておき(Akka Persistence)、 これらを再⽣することで状態を復元できる • 1万円引落 • 1万円引落 • 3万円預⼊ 「スケールアウトしやすいようステートレスに」、 から「ステートフルでスケーラブルに」 イベントの永続化 イベントの再⽣ 1万円引落し 1万円引落し ATM モバイル ⼝座 残⾼ 1万円 イベントソーシング
  • 17. Copyright © 2018 TIS Inc. All rights reserved. 17 2) インタラクティブな機能を作りたい メッセージパッシングなので基本プッシュ ポーリング @Bob “こんにちは!” Alice Bob プッシュ Alice Bob チャットサーバー トラディショナル Akka
  • 18. Copyright © 2018 TIS Inc. All rights reserved. チャットサーバー メンションサーバー - 時間的疎結合:メッセージの応答を待たない - 機能的疎結合:送信後どうなったか知らない - 位置的疎結合:別サーバーにいてもいい 18 3) サービスを分離して疎結合にしたい メッセージパッシングなので元々⾮同期で疎結合 • 密結合は複雑度をあげる • 変更容易=技術的負債になりづらい、ほどよい疎結合 「メンション」がメッセー ジを受信したときのふる まいを定義するだけ 「メンション」のふるまい が変わっても「会話」は影 響を受けない チャット エンキュー デキュー 会話 メンションMeメンション トラディショナル Akka
  • 19. Copyright © 2018 TIS Inc. All rights reserved. 19 4) システム全体の障害を避けたい アクターでエラーが発⽣したらスーパーバイザーへ コーヒ1本 故障!! システムをダウンさせないよう、 すべての障害を想定しCatch ⾃販機でコーヒーを買う try { vendingMachine.buy() } catch () { // ⾃販機の故障など // 障害が発⽣したときの処理 } 障害制御はスーパーバイザーに任せる Dave ⾃販機 スーパーバイザー トラディショナル Akka - 障害制御においても疎結合 (⾃動販売機の故障はコーヒーを買った⼈では なく⾃動販売機の管理者が対処)
  • 20. Copyright © 2018 TIS Inc. All rights reserved. 20 スーパーバイザーヒエラルキー https://doc.akka.io/docs/akka/2.5/general/supervision.html Akkaは適切な単位で障害制御を⾏うため、スーパーバイザーヒエラルキーを持つ
  • 21. Copyright © 2018 TIS Inc. All rights reserved. 21 1)データを耐久性のあるものにしたい DB  インメモリーで状態を持ちイベントを永続化 2)インタラクティブな機能を実装したい ポーリング  メッセージパッシング 3)サービスを分離して疎結合にしたい キュー  アクター間は疎結合 4)システム全体の障害を避けたい 全障害シナリオをキャッチ  コンポーネント間で影響なし トラディショナルスタイルとAkkaを4つのケースで⽐較してみた
  • 22. Copyright © 2018 TIS Inc. All rights reserved. 最小のAkkaアプリケーション 22 •クローンとビルドとインターフェイスのテスト •アプリケーションでのActorの探求 •クラウドへ
  • 23. Copyright © 2018 TIS Inc. All rights reserved. 23 クローンとビルド • github.com からサンプルプロジェクトをクローン $git clone https://github.com/yugolf/akka-in-action-java.git $cd akka-in-action-java/chapter-up-and-running/ $mvn compile exec:exec https://github.com/yugolf/akka-in-action-java/tree/master/chapter-up-and-running • ビルドとアプリケーションの起動 Slf4jLogger: Slf4jLogger started Main: start actor system: go-ticks Main: Server online at http://0.0.0.0:5000 Main: Press RETURN to stop... ※Mavenがインストールされていない場合はmvnwを使⽤してください。 例) ./mvnw compile exec:exec https://github.com/takari/maven-wrapper ※事前準備でクローン済の⼈はgit pull で最新を取得してください。
  • 24. Copyright © 2018 TIS Inc. All rights reserved. 24 プロジェクトの構成 プロジェクトの構造 リソース ソースコード テストコード ビルド成果物 Mavenのビルドファイル https://www.jetbrains.com/idea/download/
  • 25. Copyright © 2018 TIS Inc. All rights reserved. 25 構築するアプリケーション • イベント⼀覧の参照 • チケットの購⼊ • イベントの作成 • イベントのキャンセル チケット販売サービス GoTicks.com イベント管理者 お客さん
  • 26. Copyright © 2018 TIS Inc. All rights reserved. 26 Web API確認のための準備 まずは、動かしてみましょう! HTTPリクエストのツールをインストールしてアプリを起動 • HTTPリクエスト送信ツールのインストール • HTTPie または Advanced REST client - CLI: HTTPie (https://httpie.org/) - GUI: Advanced REST client(Chrome Extensions) https://chrome.google.com/webstore/detail/advanced-rest- client/hgmloofddffdnphfgcellkdfbfbjeloo $brew install httpie
  • 27. Copyright © 2018 TIS Inc. All rights reserved. 27 HTTPieでリクエスト送信 • CLI: HTTPie $http POST localhost:5000/events/JJUG/ tickets:=3 HTTP/1.1 201 Created Content-Length: 27 Content-Type: application/json Date: Sun, 02 Dec 2018 06:42:52 GMT Server: GoTicks.com REST API { "name": "JJUG", "tickets": 3 }
  • 28. Copyright © 2018 TIS Inc. All rights reserved. 28 REST clientでリクエスト送信 • GUI: Advanced REST client(Chrome Extensions) (1) (2) (3) (4) (8) http://localhost:5000/events/JJUG (5) (6) (7) {"tickets":3}
  • 29. Copyright © 2018 TIS Inc. All rights reserved. 29 APIのエンドポイント HTTPieコマンド • イベント作成 • チケット購⼊ • イベント⼀覧取得 • イベント取得 • イベントキャンセル $http POST localhost:5000/events/JJUG/ tickets:=3 $http GET localhost:5000/events $http POST localhost:5000/events/JJUG/tickets tickets:=2 $http DELETE localhost:5000/events/JJUG/ 機能 HTTPメソッド パス JSON イベント作成 POST /events/<イベント名>/ {"tickets":<枚数>} チケット購⼊ POST /events/<イベント名>/tickets/ {"tickets":<枚数>} イベント⼀覧 GET /events/ イベント取得 GET /events/<イベント名>/ イベントキャンセル DELETE /events/<イベント名>/ $http GET localhost:5000/events/JJUG/
  • 30. Copyright © 2018 TIS Inc. All rights reserved. 30 >イベント⼀覧の取得 >「JJUG」を2枚購⼊ >イベント⼀覧の取得 >「JJUG」を8枚購⼊ >「JJUG」を2枚購⼊ >チケット10枚の「JJUG」イベントを作成 >チケット20枚の「ScalaMatsuri」イベントを作成 >「ScalaMatsuri」をキャンセル >イベント⼀覧の取得 チケット販売サービスを使ってみる イベント管理者 お客さん
  • 31. Copyright © 2018 TIS Inc. All rights reserved. 最小のAkkaアプリケーション 31 •クローンとビルドとインターフェイスのテスト •アプリケーションでのActorの探求 •クラウドへ
  • 32. Copyright © 2018 TIS Inc. All rights reserved. 32 ハンズオン⽤のブランチを取得 ワークショップ⽤ブランチの取得 $ git checkout handson
  • 33. Copyright © 2018 TIS Inc. All rights reserved. ActorSystem “go-ticks” 33 クラス構成 Main HTTP Server run new create create create Actor BoxOffice Actor TicketSeller HTTP Route RestApi
  • 34. Copyright © 2018 TIS Inc. All rights reserved. Interface ITicketSeller Interface IBoxOffice 34 アクターの関係 JJUG Scala Matsuri boxOffice create Add/Buy/Cancel/… Actor BoxOffice Actor TicketSeller
  • 35. Copyright © 2018 TIS Inc. All rights reserved. Exercise 0. アクターシステムの生成 35 演習0.アクターシステムの⽣成
  • 36. Copyright © 2018 TIS Inc. All rights reserved. ActorSystem “go-ticks” 36 アクターシステムの⽣成 アクターシステムの⽣成 Main HTTP Server HTTP Route RestApi Actor BoxOffice Actor TicketSeller run new create create create
  • 37. Copyright © 2018 TIS Inc. All rights reserved. 37 「go-ticks」 ActorSystemを⽣成する 0.0.[Main] ActorSystemの⽣成 アプリケーションの実⾏ final ActorSystem system = ActorSystem.create("go-ticks"); $ mvn compile exec:exec ... Slf4jLogger: Slf4jLogger started Main: start actor system: go-ticks Main: Server online at http://0.0.0.0:5000 Main: Press RETURN to stop... ※Mavenがインストールされていない場合はmvnwを使⽤してください。 例) ./mvnw compile exec:exec https://github.com/takari/maven-wrapper
  • 38. Copyright © 2018 TIS Inc. All rights reserved. Exercise 1. イベントの作成 38 演習1.イベントの作成
  • 39. Copyright © 2018 TIS Inc. All rights reserved. 39 HTTP Route RestApi Actor BoxOffice Actor TicketSeller CreateEvent create EventCreated EventExists POST /events/JJUG Created 201 BadRequest 400 Add イベント作成時のメッセージの流れ
  • 40. Copyright © 2018 TIS Inc. All rights reserved. 40 イベント作成時のメッセージの流れ:実装箇所 実装するところ Actorの⽣成とメッセージ送信(Add/ EventCreated) HTTP Route RestApi Actor BoxOffice Actor TicketSeller CreateEvent create AddEventCreated EventExists POST /events/JJUG Created 201 BadRequest 400
  • 41. Copyright © 2018 TIS Inc. All rights reserved. 41 実装: アクターの⽣成・定義とメッセージ送信 演習1:TicketSellerアクターの⽣成、Addメッセージ の送信、EventCreatedメッセージの返信 • TicketSellerアクターの⽣成 1.1.[TicketSeller] アクターのファクトリーメソッドを定義 1.2.[BoxOffice ] TicketSellerアクターの⽣成 • BoxOfficeアクターからTicketSellerアクターへAddメッセージを送信 1.3.[TicketSeller] メッセージプロトコルの定義 1.4.[TicketSeller] メッセージ受信時のふるまい定義 1.5.[BoxOffice ] Addメッセージの送信 • BoxOfficeからRestApiへEventCreatedメッセージを返信 1.6.[BoxOffice ] EventCreatedメッセージの返信
  • 42. Copyright © 2018 TIS Inc. All rights reserved. 42 テストによる実⾏結果の確認 RestApiTest#testCreateEventの実⾏ $mvn test -Dtest=RestApiTest#testCreateEvent ... ------------------------------------------------------- T E S T S ------------------------------------------------------- Running com.goticks.RestApiTest Slf4jLogger: Slf4jLogger started Slf4jLogger: Slf4jLogger started RestApi: ---------- POST /events/RHCP/ {"tickets":3} ---------- BoxOffice: 📩 IBoxOffice.CreateEvent[name=RHCP,tickets=3] TicketSeller: 📩 ITicketSeller.Add[tickets=[ITicketSeller.Ticket[id=1], ITicketSeller.Ticket[id=2], ITicketSeller.Ticket[id=3]]] RestApi: 📩 IBoxOffice.EventCreated[event=IBoxOffice.Event[name=RHCP,tickets=3]] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.634 sec Results : Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 ... ※Windowsだと「📩 」が「?」で表⽰されます。
  • 43. Copyright © 2018 TIS Inc. All rights reserved. 43 実装1/3 TicketSellerアクターの⽣成 1.1.[TicketSeller] アクターのファクトリーメソッドを定義 1.2.[BoxOffice ] TicketSellerアクターの⽣成 public static Props props(String event) { return Props.create(TicketSeller.class, () -> new TicketSeller(event)); } public class BoxOffice extends AbstractActor { ... private ActorRef createTicketSeller(String name) { return getContext().actorOf(TicketSeller.props(name), name); } BoxOffice TicketSeller create
  • 44. Copyright © 2018 TIS Inc. All rights reserved. 44 実装2/3 BoxOfficeからTicketSellerにAddメッセージを送信 1.3.[TicketSeller] メッセージプロトコルの定義 1.4.[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
  • 45. Copyright © 2018 TIS Inc. All rights reserved. 45 実装3/3 BoxOfficeからTicketSellerにAddメッセージを送信 1.5.[BoxOffice ] Addメッセージの送信 1.6.[BoxOffice ] EventCreatedメッセージの返信 private void createEvent(CreateEvent createEvent) { log.debug(msg, createEvent); Optional<ActorRef> child = getContext().findChild(createEvent.getName()); if (child.isPresent()) { getContext().sender().tell(new EventExists(), self()); } else { ActorRef ticketSeller = createTicketSeller(createEvent.getName()); List<TicketSeller.Ticket> newTickets = IntStream.rangeClosed(1, createEvent.getTickets()) .mapToObj(ticketId -> (new TicketSeller.Ticket(ticketId))) .collect(Collectors.toList()); ticketSeller.tell(new TicketSeller.Add(newTickets), getSelf()); getContext().sender().tell(new EventCreated(new Event(createEvent.getName(), createEvent.getTickets())), getSelf()); } } BoxOffice TicketSeller Add RestApi BoxOffice EventCreated
  • 46. Copyright © 2018 TIS Inc. All rights reserved. 46 Exercise1のポイント • Actorの⽣成 • メッセージの送信 • メッセージ受信時のふるまい • メッセージプロトコルの定義 getContext().actorOf(TicketSeller.props(name), name); eventTickets.tell(new TicketSeller.Add(newTickets), getSelf()); public static class Add{ private final List<Ticket> tickets; public Add(List<Ticket> tickets) { this.tickets = Collections.unmodifiableList(new ArrayList<>(tickets)); } public List<Ticket> getTickets() { return tickets; } } @Override public Receive createReceive() { return receiveBuilder() .match(Add.class, this::add) .build(); public static Props props(String event) { return Props.create(TicketSeller.class, () -> new TicketSeller(event)); }
  • 47. Copyright © 2018 TIS Inc. All rights reserved. Exercise 2. チケットの購入 演習2.チケットの購⼊
  • 48. Copyright © 2018 TIS Inc. All rights reserved. 48 チケット購⼊時のメッセージの流れ チケットを購⼊するフロー GetTicketsPOST /events/JJUG/tickets Created 201 NotFound 404 HTTP Route RestApi Actor BoxOffice Actor TicketSeller Buy Tickets
  • 49. Copyright © 2018 TIS Inc. All rights reserved. 49 GetTickets Buy Tickets POST /events/JJUG/tickets Created 201 NotFound 404 HTTP Route RestApi Actor BoxOffice Actor TicketSeller 実装するところ メッセージ送信(Buy/ Tickets) チケット購⼊時のメッセージの流れ:実装箇所
  • 50. Copyright © 2018 TIS Inc. All rights reserved. 50 実装: Buyメッセージの送信とTicketsメッセージの返信 • BoxOfficeからTicketSellerへBuyメッセージを送信 2.1.[TicketSeller] メッセージプロトコルの定義 2.2.[TicketSeller] メッセージ受信時のふるまい - 送信元へTicketsメッセージの返信 2.3.[BoxOffice ] Buyメッセージの転送 ※TicketSellerからのメッセージの返信先を⾃⾝(BoxOffice)ではなく、 RestApi(TicketSellerいメッセージを送った⼈)にしたい 2.4.[BoxOffice ] 空のTicketsメッセージを返信
  • 51. Copyright © 2018 TIS Inc. All rights reserved. 51 チケット購⼊の動作確認 $mvn test -Dtest=RestApiTest#testBuy ... ------------------------------------------------------- T E S T S ------------------------------------------------------- Running com.goticks.RestApiTest Slf4jLogger: Slf4jLogger started Slf4jLogger: Slf4jLogger started RestApi: ---------- POST /events/RHCP/ {"tickets":3} ---------- BoxOffice: 📩 IBoxOffice.CreateEvent[name=RHCP,tickets=3] TicketSeller: 📩 ITicketSeller.Add[tickets=[ITicketSeller.Ticket[id=1], ITicketSeller.Ticket[id=2], ITicketSeller.Ticket[id=3]]] RestApi: 📩 IBoxOffice.EventCreated[event=IBoxOffice.Event[name=RHCP,tickets=3]] RestApi: ---------- POST /events/RHCP/tickets/ {"tickets":2} ---------- BoxOffice: 📩 IBoxOffice.GetTickets[event=RHCP,tickets=2] TicketSeller: 📩 ITicketSeller.Buy[tickets=2] RestApi: 📩 ITicketSeller.Tickets[event=RHCP,entries=[ITicketSeller.Ticket[id=1], ITicketSeller.Ticket[id=2]]] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.577 sec Results : Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 ... テストによる実⾏結果の確認 RestApiTest#testBuyの実⾏
  • 52. Copyright © 2018 TIS Inc. All rights reserved. 52 実装1/2 BoxOfficeからTicketSellerへBuyメッセージを送信 2.1.[TicketSeller] メッセージプロトコルの定義 2.2.[TicketSeller] メッセージ受信時のふるまい - 送信元へTicketsメッセージの返信 interface ITicketSeller { class Buy extends AbstractMessage { private final int tickets; public Buy(int tickets) { this.tickets = tickets; } public int getTickets() { return 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()); } }
  • 53. Copyright © 2018 TIS Inc. All rights reserved. 53 実装2/2 BoxOfficeからTicketSellerへBuyメッセージを送信 2.3.[BoxOffice ] Buyメッセージの転送 2.4.[BoxOffice ] 空のTicketsメッセージを返信 if (child.isPresent()) child.get().forward(new TicketSeller.Buy(getTickets.getTickets()), getContext()); else getContext().sender().tell(new TicketSeller.Tickets(getTickets.getEvent()), getSelf()); BoxOffice TicketSeller Buy BoxOffice Tickets
  • 54. Copyright © 2018 TIS Inc. All rights reserved. 54 Exercise2のポイント • メッセージの転送 child.get().forward(new TicketSeller.Buy(getTickets.getTickets()), getContext()); ※⾃⾝ではなく、⾃⾝へメッセージを送ってきた⼈に直接返信してほしいときは forwardを使う
  • 55. Copyright © 2018 TIS Inc. All rights reserved. Exercise 3. イベント一覧の取得 55 演習3.イベント⼀覧の取得
  • 56. Copyright © 2018 TIS Inc. All rights reserved. 56 イベント取得時のメッセージの流れ イベント⼀覧を取得するフロー GetEventGET /events/JJUG OK 200 Events HTTP Route RestApi Actor BoxOffice Actor TicketSeller empty GetEvent Event
  • 57. Copyright © 2018 TIS Inc. All rights reserved. 57 イベント⼀覧取得時のメッセージの流れ イベント⼀覧を取得するフロー GetEventsGET /events/ OK 200 Events HTTP Route RestApi Actor BoxOffice Actor TicketSeller GetEvent empty GetEvent Event Events
  • 58. Copyright © 2018 TIS Inc. All rights reserved. 58 GetEvents GetEvent Event GET /events/ OK 200 Events GetEvent empty Events HTTP Route RestApi Actor BoxOffice Actor TicketSeller イベント⼀覧取得時のメッセージの流れ:実装箇所
  • 59. Copyright © 2018 TIS Inc. All rights reserved. 59 実装: GetEventメッセージの送信とEventsメッセージの返信 • TicketSellerにGetEventメッセージを送信する(準備) 3.1.[TicketSeller] メッセージプロトコルの定義 3.2.[TicketSeller] メッセージ受信時のふるまい - Eventメッセージの返信 • BoxOfficeから⾃⾝にGetEventメッセージを送信 3.3.[BoxOffice ] ⾃分宛てにGetEventメッセージを送信 • BoxOfficeにGetEventメッセージ受信時のふるまいを定義 3.4.[BoxOffice ] ⼦アクターが存在する場合: - ⼦アクター(TicketSeller)へGetEventメッセージを転送 3.5.[BoxOffice ] ⼦アクターが存在しない場合: - Optional.empty()メッセージを返信 • BoxOfficeからEventsメッセージの返信 3.6.[BoxOffice ] Eventsメッセージを送信元へ返信
  • 60. Copyright © 2018 TIS Inc. All rights reserved. 60 テストによる実⾏結果の確認 チケット⼀覧取得の動作確認 $mvn test -Dtest=RestApiTest#testGetEvents ... ------------------------------------------------------- T E S T S ------------------------------------------------------- Running com.goticks.RestApiTest Slf4jLogger: Slf4jLogger started Slf4jLogger: Slf4jLogger started RestApi: ---------- POST /events/RHCP/ {"tickets":3} ---------- BoxOffice: 📩 IBoxOffice.CreateEvent[name=RHCP,tickets=3] TicketSeller: 📩 ITicketSeller.Add[tickets=[ITicketSeller.Ticket[id=1], ITicketSeller.Ticket[id=2], ITicketSeller.Ticket[id=3]]] RestApi: 📩 IBoxOffice.EventCreated[event=IBoxOffice.Event[name=RHCP,tickets=3]] RestApi: ---------- GET /events/ ---------- BoxOffice: 📩 IBoxOffice.GetEvents[] BoxOffice: 📩 IBoxOffice.GetEvent[name=RHCP] TicketSeller: 📩 ITicketSeller.GetEvent[] RestApi: 📩 IBoxOffice.Events[events=[IBoxOffice.Event[name=RHCP,tickets=3]]] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.186 sec Results : Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 RestApiTest#testGetEventsの実⾏
  • 61. Copyright © 2018 TIS Inc. All rights reserved. 61 実装1/4 TicketSellerにGetEventメッセージを送信する(準備) 3.1.[TicketSeller] メッセージプロトコルの定義 3.2.[TicketSeller] メッセージ受信時のふるまい - Eventメッセージの返信 @Override public Receive createReceive() { return receiveBuilder() .match(GetEvent.class, this::getEvent) .build(); } class GetEvent extends AbstractMessage { } BoxOffice TicketSeller Event private void getEvent(GetEvent getEvent) { log.debug(msg, getEvent); sender().tell(Optional.of(new BoxOffice.Event(event, tickets.size())), self()); } GetEvent
  • 62. Copyright © 2018 TIS Inc. All rights reserved. 62 実装2/4 BoxOfficeから⾃⾝にGetEventメッセージを送信 GetEventメッセージを⾃⾝(self)に送信する 3.3.[BoxOffice ] GetEventメッセージを⾃分宛てに送信 // 子アクター(TicketSeller)に ask した結果のリストを作成 List<CompletableFuture<Optional<Event>>> children = new ArrayList<>(); getContext().getChildren().forEach(child -> children.add(ask(getSelf(), new GetEvent(child.path().name()), timeout) .thenApply(event -> (Optional<Event>) event) .toCompletableFuture())); BoxOffice GetEvent
  • 63. Copyright © 2018 TIS Inc. All rights reserved. 63 実装3/4 BoxOfficeにGetEventメッセージ受信時のふるまいを定義 3.4.[BoxOffice ] ⼦アクターが存在する: - ⼦アクターへGetEventメッセージを転送 3.5.[BoxOffice ] ⼦アクターが存在しない: - Optional.empty()を返信 private void getEvent(GetEvent getEvent) { log.debug(msg, getEvent); Optional<ActorRef> child = getContext().findChild(getEvent.getName()); if (child.isPresent()) child.get().forward(new TicketSeller.GetEvent(), getContext()); else getContext().sender().tell(Optional.empty(), getSelf()); } BoxOffice TicketSeller GetEvent Optional.empty()
  • 64. Copyright © 2018 TIS Inc. All rights reserved. 64 実装4/4 BoxOfficeからEventsメッセージを返信 pipeを使って、処理完了時にFuture内の値(Events) を送信元に返信する 3.6.[BoxOffice ] Eventsメッセージを送信元へ返信 private void getEvents(GetEvents getEvents) { // 子アクター(TicketSeller)に ask した結果のリストを作成 List<CompletableFuture<Optional<Event>>> children = new ArrayList<>(); getContext().getChildren().forEach(child -> children.add(ask(getSelf(), new GetEvent(child.path().name()), timeout) .thenApply(event -> (Optional<Event>) event) .toCompletableFuture())); // List<CompletableFuture<Optional<Event>>> の children を // CompletionStage<Events> に変換 // Events は List<Event> を持つ CompletionStage<Events> futureEvents = CompletableFuture .allOf(children.toArray(new CompletableFuture[0])) .thenApply(ignored -> { List<Event> events = children.stream() .map(CompletableFuture::join) .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toList()); return new Events(events); }); pipe(futureEvents, getContext().dispatcher()).to(sender()); } RestApi BoxOffice Events
  • 65. Copyright © 2018 TIS Inc. All rights reserved. 65 Exercise3のポイント 応答が必要なメッセージ、⾃⾝へのメッセージ送信 レスポンスが必要な場合のメッセージ送信 ⾃分宛てのメッセージ送信 ask(getSelf(), new GetEvent(child.path().name()), timeout) .thenApply(event -> (Optional<Event>) event); pipe(futureEvents, getContext().dispatcher()).to(sender()); ask(getSelf(), new GetEvent(child.path().name()), timeout) ※レスポンスがほしいときはaskを使う(使いすぎ注意) ※pipeでCompletableFuture完了時結果を返す
  • 66. Copyright © 2018 TIS Inc. All rights reserved. Exercise 4. イベントのキャンセル 66 演習4.イベントのキャンセル
  • 67. Copyright © 2018 TIS Inc. All rights reserved. 67 イベントキャンセルのメッセージの流れ イベントをキャンセルするフロー CancelEvent Cancel Event DELETE /events/JJUG OK 200 NotFound 404 empty PoisonPill HTTP Route RestApi Actor BoxOffice Actor TicketSeller
  • 68. Copyright © 2018 TIS Inc. All rights reserved. 68 CancelEvent Cancel Event DELETE /events/JJUG empty PoisonPill HTTP Route RestApi Actor BoxOffice Actor TicketSeller イベントキャンセルのメッセージの流れ:実装箇所 実装するところ メッセージ送信(Cancel/ Event)、アクターの停⽌ OK 200 NotFound 404
  • 69. Copyright © 2018 TIS Inc. All rights reserved. 69 実装: Cancelメッセージの送信とTicketSellerアクターの停⽌ 演習4:Cancelメッセージの送信とTicketSellerアク ターの停⽌ BoxOfficeからTicketSellerへCancelメッセージを送信 4.1.[TicketSeller] メッセージプロトコルの定義 4.2.[TicketSeller] メッセージ受信時のふるまい Eventメッセージの返信 ⾃分宛てにPoisonPillメッセージの送信 ※毒薬を飲んで⾃殺 4.3.[BoxOffice ] ⼦アクターが存在する場合: - ⼦アクター(TicketSeller)へCancelメッセージを転送 4.4.[BoxOffice ] ⼦アクターが存在しない場合: - Optional.empty()メッセージを返信
  • 70. Copyright © 2018 TIS Inc. All rights reserved. 70 テストによる実⾏結果の確認 $mvn test -Dtest=RestApiTest#testCancel ... ------------------------------------------------------- T E S T S ------------------------------------------------------- Running com.goticks.RestApiTest Slf4jLogger: Slf4jLogger started Slf4jLogger: Slf4jLogger started RestApi: ---------- POST /events/RHCP/ {"tickets":3} ---------- BoxOffice: 📩 IBoxOffice.CreateEvent[name=RHCP,tickets=3] TicketSeller: 📩 ITicketSeller.Add[tickets=[ITicketSeller.Ticket[id=1], ITicketSeller.Ticket[id=2], ITicketSeller.Ticket[id=3]]] RestApi: 📩 IBoxOffice.EventCreated[event=IBoxOffice.Event[name=RHCP,tickets=3]] RestApi: ---------- DELETE /events/RHCP/ ---------- BoxOffice: 📩 IBoxOffice.CancelEvent[name=RHCP] TicketSeller: 📩 ITicketSeller.Cancel[] RestApi: 📩 Optional[IBoxOffice.Event[name=RHCP,tickets=3]] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.679 sec Results : Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 RestApiTest#testCancelの実⾏
  • 71. Copyright © 2018 TIS Inc. All rights reserved. 71 実装1/2 BoxOfficeからTicketSellerへCancelメッセージの送信 4.1.[TicketSeller] メッセージプロトコルの定義 4.2.[TicketSeller] メッセージ受信時のふるまい - Eventメッセージの返信 - ⾃⾝にPoisonPillメッセージを送信する(PoisonPillを受信するとアクターは停⽌する) class Cancel extends AbstractMessage { } @Override public Receive createReceive() { return receiveBuilder() .match(Cancel.class, this::cancel) .build(); } private void cancel(Cancel cancel){ log.debug(msg, cancel); sender().tell(Optional.of(new BoxOffice.Event(event, tickets.size())), self()); self().tell(PoisonPill.getInstance(), self()); } BoxOffice TicketSeller Event Cancel PoisonPill
  • 72. Copyright © 2018 TIS Inc. All rights reserved. 72 実装2/2 BoxOfficeからTicketSellerへCancelメッセージの送信 4.3.[BoxOffice ] ⼦アクターが存在する場合: - ⼦アクター(TicketSeller)へCancelメッセージを転送 4.4.[BoxOffice ] ⼦アクターが存在しない場合: - Optional.empty()メッセージを返信 private void cancelEvent(CancelEvent cancelEvent) { log.debug(msg, cancelEvent); Optional<ActorRef> child = getContext().findChild(cancelEvent.getName()); if (child.isPresent()) child.get().forward(new TicketSeller.Cancel(), getContext()); else getContext().sender().tell(Optional.empty(), getSelf()); } BoxOffice TicketSeller Cancel Optional.empty()
  • 73. Copyright © 2018 TIS Inc. All rights reserved. 73 Exercise4のポイント 応答が必要なメッセージ、⾃⾝へのメッセージ送信 アクターはPoisonPillメッセージを受信すると停⽌する self().tell(PoisonPill.getInstance(), self()); ※PoisonPillはActorを殺すための毒薬
  • 74. Copyright © 2018 TIS Inc. All rights reserved. Exercise 5. APIに仕立てる(解説) 74
  • 75. Copyright © 2018 TIS Inc. All rights reserved. 75 APIのエンドポイント(再掲) HTTPieコマンド • イベント作成 • チケット購⼊ • イベント⼀覧取得 • イベント取得 • イベントキャンセル $http POST localhost:5000/events/JJUG/ tickets:=3 $http GET localhost:5000/events $http POST localhost:5000/events/JJUG/tickets tickets:=2 $http DELETE localhost:5000/events/JJUG/ 機能 HTTPメソッド パス JSON イベント作成 POST /events/<イベント名>/ {"tickets":<枚数>} チケット購⼊ POST /events/<イベント名>/tickets/ {"tickets":<枚数>} イベント⼀覧 GET /events/ イベント取得 GET /events/<イベント名>/ イベントキャンセル DELETE /events/<イベント名>/ $http GET localhost:5000/events/JJUG/
  • 76. Copyright © 2018 TIS Inc. All rights reserved. 76 エンドポイントの作成(Akka HTTP) RestAPI#createRoute import akka.http.javadsl.server.Route; public Route createRoute() { return route( pathPrefix("events", () -> route( getEvents(), pathPrefix(segment(), (String name) -> route( getEvent(name), createEvent(name), cancelEvent(name) )), pathPrefix(segment().slash(segment("tickets")), (String event) -> route( requestTickets(event) )) )) ); } • AkkaHTTPが提供するDSLを使ってHTTPリクエストの制御⽅法を定義
  • 77. Copyright © 2018 TIS Inc. All rights reserved. 77 RestApi#getEvents private Route getEvents() { // [Get all events] GET /events/ return get(() -> pathEndOrSingleSlash(() -> { log.debug("---------- GET /events/ ----------"); CompletionStage<Events> events = ask(boxOfficeActor, new GetEvents(), timeout) .thenApply((Events.class::cast)); return onSuccess(() -> events, maybeEvent -> { log.debug(msg, maybeEvent); return completeOK(maybeEvent, Jackson.marshaller()); }); }) ); } エンドポイントの作成(Akka HTTP)
  • 78. Copyright © 2018 TIS Inc. All rights reserved. 最小のAkkaアプリケーション 78 •クローンとビルドとインターフェイスのテスト •アプリケーションでのActorの探求 •クラウドへ
  • 79. Copyright © 2018 TIS Inc. All rights reserved. 79 クラウドへ1/2 Heroku上にアプリケーションを乗せる • Mainクラスに標準⼊⼒を待ち受けサーバーをダウンさせる実装があるため Heroku上で動かすにはこの部分を削除 $cd .. $heroku login $heroku create go-ticks Creating ⬢ go-ticks... done https://go-ticks.herokuapp.com/ | https://git.heroku.com/go-ticks.git Heroku CLIのインストール $brew install heroku System.in.read(); log.info("presses return..."); binding .thenCompose(ServerBinding::unbind) .thenAccept(unbound -> system.terminate());
  • 80. Copyright © 2018 TIS Inc. All rights reserved. 80 クラウドへ2/2 Herokuにソースコードをプッシュ $git subtree push --prefix chapter-up-and-running heroku master .... remote: -----> Compressing... remote: Done: 73M remote: -----> Launching... remote: Released v3 remote: https://go-ticks.herokuapp.com/ deployed to Heroku remote: remote: Verifying deploy... done. To https://git.heroku.com/go-ticks.git * [new branch] 0f4dac16e9abbdbb694502f21d314281c6affd66 -> master $ http POST go-ticks.herokuapp.com/events/JJUG tickets:=250 $ http POST go-ticks.herokuapp.com/events/JJUG/tickets tickets:=4 Heroku上のアプリケーションにアクセス ※chapter-up-and-running配下のプロジェクトをプッシュする
  • 81. Copyright © 2018 TIS Inc. All rights reserved. さいごに 81
  • 82. Copyright © 2018 TIS Inc. All rights reserved. 82 さいごに やったこと • Akkaを使って⼩さなWebサービスを構築 残された課題 • アプリケーションを再起動するとデータは消える • スケールアップもスケールアウトもしない • テストを実装していない • 1台のサーバーがダウンするとシステム全体がダウンする Akkaのエコシステムで解決できるのでぜひチャレンジしてください。 https://akka.io/docs/ Akka Actors Akka Http Akka Cluster Cluster Sharing Distributed Data Akka Persistence Alpakka
  • 83. Copyright © 2018 TIS Inc. All rights reserved. チャレンジのお供に 83 • メニーコア時代のパラダイム リアクティブシステムを知ろう(ThinkIT) サンプルコードはScalaで書かれ いますが、付録でJavaのAPIも 紹介しています 本⽇のサンプルアプリケーションのScala版はこちら https://github.com/akka-ja/akka-in-action/tree/master/chapter-up-and-running
  • 84. THANK YOU We are hiring!! いっしょにチャレンジしませんか?