Slide 1

Slide 1 text

メッセージとイベントを 中核に置いた システム設計の有用性について Chatwork株式会社 加藤潤一 (@j5ik2o) アーキテクチャを突き詰める Online Conference Press Space for next page ©2024 Junichi Kato, Chatwork Inc

Slide 2

Slide 2 text

今日の話題は、 「リアクティブ・アーキテクチャ」や 「リアクティブ・マイクロサービス」というカテゴリに なります。要は、メッセージとイベントに関するお話で す。 ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 3

Slide 3 text

自己紹介 現職は Chatworkのテックリード。 Scalaや DDDを駆使した開発に 12年以上携 わってきました。技術戦略の策定から高難度な技術案件のサポートまで、幅広 く担当しています。 執筆 WEB+DB PRESS Vol.126 - 21周年記念エッセイ 今も読み続ける 1冊の本 レビュー エリックエヴァンスのドメイン駆動設計 Akka実践バイブル ドメイン駆動設計入門 良いコード/悪いコードで学ぶ設計入門 WEB+DB PRESS Vol.132 - 特集 1 オブジェクト指向神話からの脱却 趣味は Rust。最近 CQRS/Event Sourcing用ライブラリを TS,Go,Rust,JVM向 けに実装してます。 twitter: j5ik2o github: j5ik2o ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 4

Slide 4 text

今日の目的 現代のシステム設計において、メッセージとイベント駆動のアプローチは、即応性、スケーラビリティ、耐障害性を実現する ための重要な要素です。本セッションでは、その有用性と具体的な適用方法について解説します。 ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 5

Slide 5 text

アジェンダ メッセージとイベントの基礎 メッセージとイベントの技術的利点 アーキテクチャにおけるメッセージとイベントの役割 まとめ ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 6

Slide 6 text

前提 本セッションで言及するメッセージは、アラン・ケイのメッセージングとは異なり、アクターモデルのメッセージングを指し ます。アクターモデルでは、並行処理を管理しやすくするために、メッセージを通じてアクター間の通信を行います。この違 いを念頭に置いてください。 ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 7

Slide 7 text

アクターモデルとは アクターモデルは、並行計算モデルの一つ。 1973年に Carl Hewittが発明。アクターと呼ばれるプロセス同士が通信しあって 計算を行う 自らのプライベートな状態を持ち、特定のタスクを実行するための振る舞いを持っている 他のアクターとメッセージを通じてのみ通信する。メッセージを受信した際にのみ、処理が実行される 受け取ったメッセージに基づいて自身の状態を変更することができ、また新しいアクターを生成できる 主な利点は、並行性の管理が容易になること。アクターが独立して操作を行い、直接的な共有状態がないため、データ競合や ロックの問題が発生しにくくなる。これにより、多数のプロセスやスレッドが活動する大規模なシステムや、分散システムに おいて、効率的で安全な並行処理が可能になる ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 8

Slide 8 text

FYI: Chatworkでのアクターモデル採用事例 チャットメッセージ基盤 (2016〜 ) WebHook基盤 (2017〜 ) ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 9

Slide 9 text

FYI: 関連する技術キーワード アクターモデル (Akka, Pekko, Erlang/OTP, Proto.Actor, Dapr, …) リアクティブストリーム (Akka-Streams, GenStage, RxJS, …) ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 10

Slide 10 text

なぜメッセージとイベントに注目するのか ユーザー目線では、即応性(システムがいつでも使用可能であること)は「当たり前品質」 この「当たり前品質」を確保しつつ、プロダクトとしての「魅力的品質」を提供することが求められる 即応性 を実現するためには、スケーラビリティ (弾力性 )と耐障害性が必要 これらを実現するには、メッセージ駆動 が必要 メソッド駆動のアーキテクチャだけでは限界がある 今回は 非同期なメッセージング と イベント駆動アーキテクチャ にフォーカスする ユーザの要求の変化 ノード数は数十台から数百・数千コアへ レスポンスタイムは秒からミリ秒オーダーに ダウンタイムは数時間から限りなくゼロに 処理対象のデータ規模はギガからペタへ (そもそも終わり がない ) 形 ⼿段 値 即応性 拡張可能 拡張可能 耐障害性 メッセージ駆動 弾⼒性 リアクティブシステム ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 11

Slide 11 text

メッセージとイベントの基礎 ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 12

Slide 12 text

メッセージとは何か 送信者から受信者へ送られる情報の単位 具体的には、送信者が受信者に伝えたい実際のデータ(本文)とそのデータに関する追加情報(メタデータ)で構成され ます。メタデータには、メッセージのタイプ、送信者、受信者、優先度、有効期限などが含まれます メッセージを送受信することを メッセージパッシング や メッセージング と呼ぶこともある。 通信方法には、以下の設計要素が含まれる 同期通信か、非同期通信 か 配送保証の有無と保証レベル 順序通り受信されるか否か ピアツーピアか、マルチキャストか、ブロードキャストか ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 13

Slide 13 text

メッセージの送受信 (メッセージング ) ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 14

Slide 14 text

非同期メッセージによって無駄な待ち時間を削減 原則的にメッセージは送信者と受信者の間で非同期に交換される。送信者はメッセージを送信した後、受信者からの応答 を待つことなく次の処理を進められる ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 15

Slide 15 text

メールボックスによって弾力性を確保できる メッセージは、受信者側のキューに蓄積することが可能。受信者が処理可能な状態になったときに順次処理される これにより、受信者の処理能力を超えるメッセージ流量があっても、システム全体が停止することを防ぐことができる 受信者が複数存在する場合、さらに効率がよくなる。メッセージの受信者全員が同時に通信できる状態になるまで待つの は非常に非効率的であり、一度に一人の受信者に同期的にメッセージを渡すこともできない。 ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 16

Slide 16 text

FYI: アクターモデルの概念 (だいぶ雑な …) アクターモデルのメッセージ送受信部分だけを簡単に説明する図 ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 17

Slide 17 text

FYI: メッセージのサブセット コマンド (EIP: Command Message) コマンドリクエスト : 受信者へ の命令や指示。コマンドリク エスト名がメソッド、パラメ ータが引数に対応 コマンドレスポンス : コマン ド・リクエストに対応する返 信。戻り値に相当するが、こ れも非同期にメッセージ送信 しているに過ぎない イベント (EIP: Event Message) 後述 概念図 Message CommandRequest id: ULID aggregateId: AggregateId replyTo: ActorRef CommandResponse id: ULID PostMessage content: Content senderId: UserAccountId PostMessageSucceeded messageId: MessageId PostMessageFailed error: PostMessageError Event id: ULID aggregateId: AggregateId occurredAt: Instant sequenceNumber: Long MessagePosted content: Content senderId: UserAccountId ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 18

Slide 18 text

イベントとは何か ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 19

Slide 19 text

例えば GUIの文脈では、 Buttonのクリックイベント ドメインの文脈では、ショッピングカートへの商品の追加イベント ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 20

Slide 20 text

イベントは「出来事」 具体例としては、ユーザーのボタンクリックや商品の購入などが挙 げられます。 ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 21

Slide 21 text

「出来事」とは何か 「出来事」=「事実」=成立した事態 ※事態とは対象 (事柄、事物 )が結合したもの 「 2020年 コロナウィルスが流行した」は、出来事であり事実 未成立な事態は「出来事」や「事実」とは呼ばない 「 2021年 関東が沈没する」は成立していない 論理空間の扱い 概念図 事態 成⽴した事態 ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 22

Slide 22 text

イベントは過去形で表現される イベントとは、何か重要なことが起こったときに発生するもので、動詞の過去形で表現される 商品が注文された (ProductPurchased) 商品が出荷された (ProductShipped) イベントは重要な振る舞いを表すため、それらに注目することで動的な側面を理解しやすくなります ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 23

Slide 23 text

イベントは探索ツール ヒトやモノから分析すると発散しがち。コトを手がかりにすると効率的 Event Stormingはサイロを飛び越えてドメインを探索することができるツール ⼊荷 出荷 ⼊荷(コト) 出荷(コト) 商品(モノ) 担当者(ヒト) ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 24

Slide 24 text

「世界は事実の総体である」 ウィトゲンシュタインの哲学から 「 1.1 世界は、事実 の総体である。事物 の総体ではない。 」 世界が事物の総体であり、事実の総体ではないとしたら、 「ここにリンゴがあ る」 という事実すらも世界には含まれなくなってしまう つまり「事実」が中心的な要素である。事物はその「事実」の一部として存在す る。 ドメイン分析のフェーズにおいても以下の視点が役立つ 事実 : ドメインイベント 事物 : ドメインイベントに関連するドメインモデル ドメインイベントはドメイン分析のツールとして使える ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 25

Slide 25 text

メッセージとイベントの技術的利点 ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 26

Slide 26 text

メッセージの技術的利点 ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 27

Slide 27 text

メッセージの同期通信と非同期通信の比較 メッセージを送信するに当たって、両者間が同期か、非同期かの違い。 同期通信では、両者が同時に通信の準備ができている必要がある 非同期通信では、送信者は受信者の準備がでているかに関係なく送信できる ※同期通信には、相手に送信できたかわかるためのタイマーが必要になる。 同期通信 送信者 受信者 タスクを依頼する ⼀定時間 返信を待つ タスクの完了を通知する 他のタスクを実⾏する ⾮同期通信 送信者 受信者 タスクを依頼する 依頼だけを 受け取れる 他のタスクを実⾏する タスクの完了を通知する 完了通知を いつ受け取ってもいい 返信時の処理 ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 28

Slide 28 text

フロー制御を考慮したメッセージの送受信 送信レートを調節して受信側に負担が掛からないようにするプロセスのこと=フロー制御 送信側は受信側からの要求で流量を調整する。送信側にて背圧制御 (バックプレッシャ )がかかる バックプレッシャなし 送信者 受信者 メッセージを送信 メッセージを送信 メッセージを送信 処理能⼒オーバー 返信を返す 下流が遅いとき 送信者 受信者 1要素を要求 メッセージを送信 返信を返す 下流が早いとき 送信者 受信者 2要素を要求 メッセージを送信 メッセージを送信 返信を返す 返信を返す ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 29

Slide 29 text

フロー制御とメソッドの同期化との比較 一方で、ある種のフロー制御を含むメソッド呼出しにて、送信側が受信側のリソースを奪い合う場合、処理は一般的にロ ックやセマフォの同期化で直列化する必要がでてくる。これも一応暗黙的な背圧で便利だが、トラフィック量が増えると 弾力性が一気に失われる。障害に変わることが多い。しかもデバッグも厄介 メッセージは待ち行列の概念を使っていて、柔軟なフロー制御ができる。キューが満杯になったらドロップさせたり、キ ューに優先度を設けたりすることも可能 ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 30

Slide 30 text

フロー制御の典型的な利用シーン 実際に Chatwork社での実装例。下流の I/Oが処理しきれないほどの要求が発生した場合、ユースケースなどの上流の送信 レートを緩和する (バックプレッシャ ) また、下流でのエラーや障害に対して上流での処理を適切に緩めることで、連鎖的な障害の発生を防ぎ、システム全体の 安定性を保つ Akkaや Pekkoはこの手の複雑なフロー制御を引き受けることができ、開発者は本来の課題に集中できる ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 31

Slide 31 text

位置透過性( Location Transparency) 送信先がローカルかリモートかは区別しない 送信先がローカルであってもリモートのように、メッセージが即座に送信されたり即座に処理されることを前提とせず、メッ セージの送信や受信が途中で失われる可能性も考慮される。 具体的には、コンポーネント同士がメッセージをやり取りする際に、その内部構造がどのようになっているかや、コンポーネ ントがどこに配置されているかに関わらず、メッセージパッシングの抽象化によって統一される。 これにより、コンポーネント間の通信がローカルであろうがリモートであろうが、同様の方法で処理され、開発者はその違い を意識する必要がなくなる。 // groupChatRef1がリモートであってもローカルであっても、同じ方法でメッセージを送信できる groupChatRef1 ! PostMessage("Hello World", senderId, replyTo) // Java Style: groupChatRef.tell(PostMessage.of("Hello World", senderId , replyTo)); ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 32

Slide 32 text

透過的リモーティング (Transparent Remoting) 送信元がリモートかローカルかは区別しない 受信側プロセスが送信元がリモートかローカルかを区別しない仕組み。 リモートからのメッセージもあたかもローカルから届いたメッセージをハンドラに渡される。メッセージに付与される送信元 の replyToはローカルの宛先のように見えるが、実際にはリモートと接続可能なプロキシが生成される。 replyToにメッセージ を送ることができる。 // replyToはリモート上のクライアントプロキシーに該当する def greeterBehavior: Behavior[Message] = Behaviors.receive { (context, message) => message match { case Greet(who, replyTo) => // replyTo: ActorRef[Greeted] // メッセージを処理して応答 replyTo ! Greeted(who) // replyTo.tell(Greeted.of(who)); Behaviors.same // ... } } ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 33

Slide 33 text

メッセージはマルチスレッディングと RPCを統合する 位置透過性( Location Transparency) 透過的リモーティング (Transparent Remoting) によって、マルチスレッディングと RPCの区別がなくな り、クラスター上にあるすべてのコンピュータがローカル コンピュータのように扱えるようになる。 スケーリングにおけるスケールアップもスケールアウト も、すべてメッセージによって区別することなく利用可能 になり、コードを大幅に変更する必要がなくなる。 今日は詳しく話さないが、この特徴をうまく使ってコンテ キスト境界の見直しのハードルを下げることができる ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 34

Slide 34 text

イベントの技術的利点 ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 35

Slide 35 text

イベントのアーキテクチャ上の有用性 実装上でも有用! イベントとは、システム内で発生した出来事を表すメッセージの一種。以下のような特徴を持ちます。 状態変化の通知 (Pub/Sub) イベントは、システムの状態が変化したことを 他のコンポーネントに通知するために 使われる 例えば、ユーザーがボタンをクリックした、新しいデータが到着した、タイマーが期限に達したなどの出来事が、イベ ントとして表現される 不変の事実記録と状態構築 (Event Sourcing) イベントは、システム内で起きた具体的な事実を記録する。これらのイベントは変更不可能で、一度発生したら取り消 すことはできない システムの状態はこれらの事実に基づいており、イベントの集合を使って任意の時点でのシステムの状態を再構築でき る。これにより、 システムの現在の状態が過去の事実に基づいていることが保証される Pub/Subと Event Sourcingは、関係性が深いため混同しやすいが目的が異なる。 ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 36

Slide 36 text

FYI: Event Sourcingのおさらい ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 37

Slide 37 text

メッセージ vs イベント メッセージベース メッセージを特定の受信者に送ることができ、受信者はそのメッセージを処理する責任を担う。 受信者はメッセージを 1つずつ処理し、並行処理や同期を不要とする。また、メッセージへの応答は受信者の状態に基づい て変化する イベントベース 起こった事実であるイベントを受け取ったたら、システムはタスクを実行する責任を担う。 通常、イベントは発生するたびに、対応するイベントキューに追加される。イベントループはこのキューからイベントを 取出し対応するコールバックを実行する ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 38

Slide 38 text

マイクロサービスアーキテクチャにおける メッセージとイベントの有用性 ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 39

Slide 39 text

メッセージ ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 40

Slide 40 text

同期呼び出しは可用性が低くなる RPCなど同期呼びだしはわかりやすいが、 すべてのサービスが同時に利用できる状態である必要がある 。 依存先のサービス が停止すると、注文サービスに問題がない場合でも 可用性も下がってしまう 。 ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 41

Slide 41 text

非同期メッセージングを使うと可用性があがる 同期呼び出しより複雑になるが、 すべてのサービスが同時に利用できる状態である必要がない 。 ただし、メッセージキュー に相当する基盤は稼働している前提となる ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 42

Slide 42 text

集約をアクターとすれば、どこにでも配置が可能 モジュラーモノリス上でも、マイクロサービスアーキテクチャでも、アクターの位置は透過的であるため、どこに配置しても 同じように機能する。 Akka/Pekkoには集約をアクターにするための、機能が提供されている ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 43

Slide 43 text

イベント ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 44

Slide 44 text

イベントを使う技術的な利点 マイクロサービス間の疎結合 : イベントを介して通信するために、サービス間の直接的な依存関係が減少し、システム全体 の変更が容易になる 拡張性の向上 : イベントコンシューマを追加することで、新しい機能を追加することができる スケーラビリティの向上 : イベント処理を複数のコンシューマに分散させることで、負荷分散が可能になる 耐障害性の向上 : イベントの再送によって、システムの耐障害性が向上する ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 45

Slide 45 text

State Sourcing + Pub/Sub Pros シンプルな実装 : 既存のデータベースと Pub/Subシステムを使用することで、比較的簡単に実装できる 直感的なデータモデル : 現在の状態をそのままデータベースに保存するため、データモデルが直感的 Cons 2フェーズコミットの問題 : 分散トランザクションをサポートしないため、一貫性の確保が難しくなる ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 46

Slide 46 text

Event Sourcing + Pub/Sub Pros 一貫性の向上 : 同一トランザクションで処理する必要がないため、データの一貫性をより確実に保てる 過去の状態の追跡が容易 : すべてのイベントを保存するため、過去の状態を容易に再現できる スケーラビリティ : 非同期処理により、システム全体のスケーラビリティが向上する Cons 複雑な実装 : イベントストアやスナップショットの管理が必要なため、実装が複雑になる (ツールである程度はカバーで きるようになっている ) ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 47

Slide 47 text

FYI: 実装のためのツール Event Store Adatpor Amazon DynamoDB を Event Store化するためのライブラリ。スケーラビリティと耐障害性を両立 アクターモデルに限らず、従来のオブジェクトモデルでも Event Sourcingを実現可能 対応言語 : Go, Rust, Scala, Kotlin, Java, TypeScript 実施の実装例はこちら Akka Pekko Axon Proto.Actor ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 48

Slide 48 text

参考資料 Reactive Desgin Patterns マイクロサービスアーキテクチャ Awesome Domain-Driven Design Awesome Elixir and CQRS 現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法 ©2024 Junichi Kato, Chatwork Inc 1 / 49

Slide 49

Slide 49 text

まとめ メッセージとイベントの有用性および、これらがアーキテクチャに与える影響を確認しました。メッセージングとイベント駆 動設計は、現代のシステムにおいて即応性、スケーラビリティ、耐障害性を高めるために重要な役割を果たします。 今回の内容が、メッセージングとイベント駆動の理解を深める一助となれば幸いです。ぜひ、これらの概念を自身のシステム 開発に取り入れてみてください。質問やディスカッションはいつでも歓迎します。 ご清聴ありがとうございました。 ©2024 Junichi Kato, Chatwork Inc 1 / 49