Slide 1

Slide 1 text

EIPとAKKAについて かとじゅん( ) 2022/02/09 実践!インテグレーションパターン 現場から学ぶモデル駆動設計 @j5ik2o 1

Slide 2

Slide 2 text

自己紹介 Chatwork社 テックリード 副業では技術顧問として活動中 FizzBuzzを書くためだけのプログラミング言語を作りました @j5ik2o https://github.com/j5ik2o/oni-comb-rs 2

Slide 3

Slide 3 text

EIPとAKKAについて話します 3

Slide 4

Slide 4 text

具体的には 配送保証(GUARANTEED DELIVERY) のパターンを解説します が、前提知識を少し話します。 4

Slide 5

Slide 5 text

AGENDA 通信は届かない(ことがある) メッセージ配送の保証 配送保証(Guaranteed Delivery) Akkaの簡単な実装例とReliable Delivery 5

Slide 6

Slide 6 text

送信したデータが 相手に必ず届くと 思い込んでませんか? 6

Slide 7

Slide 7 text

通信は届かない(ことがある) 少なくとも現時点では失敗のないネットワークを構築することは 不可能と言われている。メッセージが欠落したり、遅延したりす る可能性は必ずある。今の技術で避けられない よく考えられたシステムは、この問題をカバーするように設計さ れている(それでも限界がある)。そのような考慮がないシステム では容易にメッセージの欠落や矛盾が起こる 7

Slide 8

Slide 8 text

「なぜ届かないのか」を理解する 8

Slide 9

Slide 9 text

アナロジー:二人の将軍問題 信頼性の低い通信チャネルでは コンセンサスに達することが不可能である Two Generals' Problem 二人の将軍問題 9

Slide 10

Slide 10 text

二人の将軍問題(1/4) 赤が敵軍、緑が同盟軍。同盟軍A or Bが単独攻撃しても数で負け るが、AとB 一緒に攻撃すれば勝てる可能性がある。しかし、軍 隊は谷間に位置しているため、旗などの遠隔通信で攻撃の時間を 指示することは不可能 彼らはコミュニケーションのために敵地を経由して使者(メッセ ンジャー)を送る。が、敵地を経由するので使者は捕まったり殺 されたりする可能性がある ⼭ ⼭ 敵軍 同盟軍A 同盟軍B 10

Slide 11

Slide 11 text

この問題は 「信頼性の低い通信路」 で何が起きるかを示している 11

Slide 12

Slide 12 text

二人の将軍問題(2/4) 将軍Aから将軍Bに「14時に攻撃する」ということをメッセンジ ャーを通じて送る。 無事に将軍Bにメッセージが届いた場合 メッセンジャーは無事に 敵地を通り抜けて、将軍Bにメッセージを伝える。 将軍A 将軍A 敵地 敵地 将軍B 将軍B 14時に攻撃する 12

Slide 13

Slide 13 text

二人の将軍問題(3/4) 将軍Bから将軍Aに返信がない場合、将軍Aはどう考えるか 将軍Aはメッセンジャーが将軍Bに到着したかを知らない。敵地 で殺されたかもしれない。将軍Bは「14時に攻撃する」を知らな い可能性がある。将軍Bが攻撃の準備ができていないかもしれな い 将軍A 将軍A 敵地 敵地 将軍B 将軍B 14時に攻撃する 了解 なので、将軍Bは「了解」ということをメッセンジャーを通じて返 信もらう必要がある(返信が来ない場合はリトライするかも) 13

Slide 14

Slide 14 text

二人の将軍問題(4/4) が、これもメッセージが将軍Aに届かない可能性がある 厳密には「了解」が伝わったかは、将軍Aからの「了解の了解」 の返信を待つ必要がある… 将軍A 将軍A 敵地 敵地 将軍B 将軍B 14時に攻撃する 了解 了解の了解?? これでは 完全に合意するには無限のメッセージを送る必要があ る… 14

Slide 15

Slide 15 text

低信頼網では 100%の合意に到達できない どんなに多くの要求を送っても、どんなに多くの返答を送っても、 将軍Aも将軍Bも相手の将軍が攻撃の準備をしていることを100% 確信することはできません。 これが「二人の将軍問題」の核心です 15

Slide 16

Slide 16 text

ネットワークを使った メッセージ配送も 信頼性の低い通信路を 使った通信の一つ 16

Slide 17

Slide 17 text

メッセージ配送には これらを考慮したモデルがある 17

Slide 18

Slide 18 text

メッセージ配送の信頼性(1/2) At-Most-Once Delivery メッセージは0回もしくは1回 配送される (tellの場合は)送ったけど相手に届かないことがある askによって返信を確認することはできる とはいえ、タイムアウトしたときリトライするなら、at- most-once以上のことをやろうとしている 高パフォーマンス・低コスト 18

Slide 19

Slide 19 text

メッセージ配送の信頼性(1/2) At-Least-Once Delivery メッセージは少なくとも1回配送が成功する 相手にメッセージが重複して届く可能性がある 送信側に必ずディスクが必要になる Exactly-Once Delivery メッセージは正確に1回だけ配送される 受信側にもディスクが必要になる デフォルトのメッセージ配送は「At-Most-Once Delivery」です。 運がよかったら届くかもね! そんなインテグレーションで大丈夫か?! 19

Slide 20

Slide 20 text

そこでEIPですよ 20

Slide 21

Slide 21 text

配送保証(GUARANTEED DELIVERY) At-Least-Once Deliveryのために 21

Slide 22

Slide 22 text

メッセージングシステムが故障して も、送信者がメッセージを確実に届 けられるようにするには? メッセージを配送するシステム=メッセージングシステム messaging system sender receiver 22

Slide 23

Slide 23 text

メッセージの保存と転送のプロセス 非同期に動作するメッセージングは送信者・受信者、そしてそれ らを繋ぐネットワークが同時に動作している必要がない(同期型 のRPCは障害に弱い) メッセージングシステムがネットワークを利用できない場合、ネ ットワークが利用可能になるまでメッセージを保存すればよい。 受信者が利用できない場合も、メッセージを保存しておき、受信 者が利用できるようになるまでリトライする。 23

Slide 24

Slide 24 text

受信者が故障で不通なら 送信者はリトライする。 リトライ中 送信者が故障しても 大丈夫? 24

Slide 25

Slide 25 text

いいえ 当然リトライ中であること も忘れます 25

Slide 26

Slide 26 text

メッセージが揮発しないように メッセージを永続化する メッセージングシステムがノード障害などを起こせば、保持して いるメッセージはすべて消失する。 対策としてファイルやデータベースなどを使ってディスクに永続 化する必要がある Apache Kafkaがまさに同じようなことをやっています(ブローカー が仲介するので厳密には同じではないが) 26

Slide 27

Slide 27 text

配送保証(GUARANTEED DELIVERY) のPROS/CONS 配送保証パターンでは、メッセージングシステムはデータストア を使ってメッセージを保存します 27

Slide 28

Slide 28 text

送信者が故障しても 復旧後にメッセージは送信される 送信側のPCのローカルに保存されます。メッセージ送信際、デ ータストアにメッセージが保存されるまで送信操作は正常に完了 しない。メッセージが正常に送信されたら、データストアからメ ッセージが削除される 28

Slide 29

Slide 29 text

信頼性を得る代わりに パフォーマンスが犠牲になる メッセージの永続性は信頼性を高めるが、パフォーマンスが犠牲 になる。メッセージ配送のクラッシュやシャットダウン時にメッ セージが失われても構わない場合は、配送保証パターンを採用し ないほうがパフォーマンスがよくなる(トレードオフ) 29

Slide 30

Slide 30 text

FYI: EXACTLY-ONCE DELIVERY = 配送保証(GUARANTEED DELIVERY) + べき等レシーバー(IDEMPOTENT RECEIVER) 30

Slide 31

Slide 31 text

AKKAでどう実装するか 31

Slide 32

Slide 32 text

簡単なモデルを示した例 network Sender«Actor» Forwarder«PersistentActor» Receiver«Actor» 32

Slide 33

Slide 33 text

登場人物 Receiver Forwarder Sender https://github.com/j5ik2o/akka-at-least-once- delivery/blob/main/src/main/scala/example/simple/Receive https://github.com/j5ik2o/akka-at-least-once- delivery/blob/main/src/main/scala/example/simple/Forwar https://github.com/j5ik2o/akka-at-least-once- delivery/blob/main/src/test/scala/example/simple/AtLeastO 33

Slide 34

Slide 34 text

この設計の問題点 リトライ間隔やリトライ上限回数がないので、リトライによって ネットワークに負荷をかける可能性がある Akkaでは指数関数バックオフに対応したBackoffSupervisorに よって解決できる メッセージの追い越しできない場合は、メッセージを蓄積しつつ フロー制御が必要になる AkkaのStashBufferでバッファリングしつつ、 akka-persistenceの機能によって受け付けたメッセージを蓄 積する このサンプルでは、故障しやすいタスクをReceiverが担う場 合、故障中のメッセージ配送をどうするかという問題がある EIPのように受信側にも故障しにくい仲介者が必要。仲介者と してSupervisorを間にいれる Akka Reliable Deliverも選択肢の一つ 34

Slide 35

Slide 35 text

AKKA RELIABLE DELIVERY https://doc.akka.io/docs/akka/current/typed/reliable- delivery.html https://github.com/j5ik2o/akka-at-least-once- delivery/tree/main/src/main/scala/example/delivery 35

Slide 36

Slide 36 text

まとめ 一般的にメッセージ配送には保証がない(TCPもHTTPもat-most- once) その代わりに高パフォーマンス・低コスト ちゃんと届けるにはそれなりの仕組みが必要になる それが配送保証(Guaranteed Delivery) 配送保証(Guaranteed Delivery)によってat-leaset-onceを実 現する Akkaには、配送保証(Guaranteed Delivery)の考え方が設計思想 に組み込まれている PersistentActorでも実現可能 Akka組込のReliable Deliveryを使うことも可能 36

Slide 37

Slide 37 text

終わり 37