Slide 1

Slide 1 text

CQRS/ES に なぜアクターモデルが 必要なのか v1.0.0 加藤潤一(@j5ik2o) CQRS/ES カンファレンス2026

Slide 2

Slide 2 text

プロフィール 加藤潤一 経歴 10 歳からプログラミング開 始 〜2011: SIer+Java+ 金融 2011 〜2014 年: ドワンゴ, グ リー 2014 〜2024 年: kubell (旧 Chatwork ) 2025 年1 月〜 IDEO PLUS 社 専門分野 ドメイン駆動設計(DDD ) 関数型プログラミング 分散システム設計 15 年以上のDDD 実践経験 | Chatwork の大規模リアーキテクチャを主導 分散システム・スケーラブルアーキテクチャのエキスパート(LAPRAS 調べ)

Slide 3

Slide 3 text

本日のアジェンダ # トピック 内容 1 オブジェクトベースCQRS/ES の限界 イベント追い越し問題と楽観的ロックの課題 2 アクターモデルの基礎と解決策 Share Nothing ・逐次処理・SSoT によるロック不要化 3 クラスタリングとVirtual Actors SPOF の課題と分散協調による解決 ゴール: CQRS/ES におけるアクターモデルの必然性を理解する

Slide 4

Slide 4 text

オブジェクトベースのCQRS/ES とその限界

Slide 5

Slide 5 text

j5ik2o/event-store-adapter 2023-2024 年に開発・公開したCQRS/ES ライブラリ群 j5ik2o/event-store-adapter j5ik2o/cqrs-es-example DynamoDB をイベントストアに使うオブジェクトベースのCQRS/ES 実装 Rust/Go/TypeScript/Java/Scala/PHP アクターシステムに頼らずEvent Sourcing する方法について

Slide 6

Slide 6 text

なぜこのライブラリを作ったか 2014 年 Akka 2.3 Persistence(Event Sourcing) がおそらくES 専用ライブラリとして初 しかし、誰もがアクターモデルを使えるわけではない、ということでオブジェクトモデルでも可能にしたと いう背景 問題になるのが、イベントを追記するときのロック獲得

Slide 7

Slide 7 text

CQRS/Event Sourcing の実装例(推奨)

Slide 8

Slide 8 text

ロック機構がない場合の「イベント追い越し・不整合」 前提: 楽観的ロック(バージョンチェック)がな い素朴な実装 シナリオ: User A が先に処理を開始。 User B が少し遅れて処理を開始。 発生する問題: " イベントの追い越し" ネットワーク遅延や処理時間のゆらぎに より、後から来た User B のイベントが先 に保存されてしまう。 結果: チャットの会話順序がおかしくなる。 「定員オーバー」などのビジネスルール (不変条件)が破られる。 最悪なのは「エラーにならずに静かにデータが 壊れる」こと。 User A User A User B User B Stateless UseCase (A) Stateless UseCase (A) Stateless UseCase (B) Stateless UseCase (B) EventStore (DynamoDB) EventStore (DynamoDB) Current State: 10 messages 1 Post Message(11) 2 Load Snapshot + Events User A sees "10 messages" 3 Post Message(12) 4 Load Snapshot + Events User B also sees "10 messages" 5 Domain Execute (Create Event 11) 6 Domain Execute (Create Event 12) 遅延やタイミングのズレにより B の書き込みが先⾏! 7 Save Event (Message 12) 8 Save Event (Message 11) Data Corruption / Inconsistency History: [..., Msg10, Msg12, Msg11] 時系列が逆転してしまう! ( もしくは同じVersion ID で上書き発⽣)

Slide 9

Slide 9 text

スライド案:解決策としての楽観的ロック(しかし… ) 解決策: バージョンによる楽観的ロック 仕組み: 書き込み時に「読み込んだ時のバージョ ン(10) 」と「現在のDB のバージョン」が 一致しているかを確認する。 DynamoDB の TransactWriteItems + ConditionExpression を利用。 結果: 整合性は担保される: バージョン不整合 (競合)時は書き込みが拒否されるた め、イベントの追い越しやデータ破壊は 起きない。 新たな課題: 競合負けしたユーザーA には エラーが返る。リトライ処理が必要にな り、クライアントの実装負担とUX 低下 を招く。 User A (Loser) User A (Loser) User B (Winner) User B (Winner) Stateless UseCase (A) Stateless UseCase (A) Stateless UseCase (B) Stateless UseCase (B) EventStore (DynamoDB) EventStore (DynamoDB) Current Version: 10 1 Post Message(11) 2 Load Snapshot + Events Reads Ver: 10 3 Post Message(12) 4 Load Snapshot + Events Reads Ver: 10 5 Domain Execute 6 Domain Execute Winner (B) Condition: "Version == 10" DB is 10 → Match! 7 TransactWrite(Event 12) IF Version = 10 8 Success (Ver updated to 11) 9 200 OK Loser (A) Condition: "Version == 10" DB is 11 → Mismatch! 1 0 TransactWrite(Event 11) IF Version = 10 1 1 TransactionCanceledException (ConditionalCheckFailed) 1 2 409 Conflict (Please Retry)

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

アクターモデルの基礎

Slide 12

Slide 12 text

アクターモデルとは 基本概念(Carl Hewitt, 1973 ) アクター: 計算の基本単位。状態・振る舞い・メ ールボックスを持つ メッセージパッシング: アクター間の唯一の通信 手段 逐次処理: 各アクターは一度に1 つのメッセージ のみ処理 アクターができること 1. メッセージを送る: 他のアクターにメッセージを 送信 2. 新しいアクターを作る: 子アクターを生成 3. 自身の状態を変える: 次のメッセージへの振る舞 いを決定

Slide 13

Slide 13 text

なぜアクターモデルで並行性が単純化されるのか 従来のスレッドモデルの問題 共有メモリ + ロックによる排他制御 デッドロック、レースコンディションのリスク 複雑な同期プリミティブの管理 アクターモデルの解決策 共有なし(Share Nothing ): 各アクターは自身 の状態のみ保持 メッセージによる通信: 状態の直接共有なし 逐次処理保証: アクター内は常にシングルスレッ ド

Slide 14

Slide 14 text

アクターによってドメイン状態をシステムに取り戻す システム全体において、そのアクターは一つしか 存在しないため、イベントの追記のためにロッ クが不要になる DB には状態はなくイベントログしか書かれな い。インピーダンスミスマッチの解消も不要( イ ンピーダンスミスマッチの解消はRead Model Updater が担う) 状態はアクター内部のオブジェクトが持つ。状態 の近くでなければドメインリッチにはならない そして アクターが信頼できる唯一の情報源 =SSoT になる ただし、アクターのクラスターとシャー ディングの機構が必要になる

Slide 15

Slide 15 text

アクターのクラスタリングとシャーディング

Slide 16

Slide 16 text

Akka/Pekko Cluster(2009-) Akka (Scala/Java), Pekko (Scala/Java) Shard Coordinator: 各シャー ドの担当ノードを管理 Shard Region: シャードの管 理とリクエストのルーティン グを行う Shard Actor: エンティティア クターが所属するアクター Entity Actor: 集約のためのア クター

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

ProtoActor Go (2022-) 意外に最近 Orleans のVirtual Actor を実 装している Grain はシャーディングされ たアクター Cluster Provider はetcd, Consul など

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

FYI: j5ik2o/fraktor-rs

Slide 21

Slide 21 text

まとめ 1. オブジェクトベースCQRS/ES の限界 ステートレスサーバーでイベントの追い越しが発 生 楽観的ロックで整合性は守れるが、リトライ負 担とUX 低下 2. アクターモデルによる解決 Share Nothing + メッセージパッシングでロック 不要 逐次処理保証でアクター内は常にシングルスレッ ド アクターが SSoT (信頼できる唯一の情報源) に 3. クラスタリングの課題と解決 Akka/Pekko: Shard Coordinator がボトルネック になりやすい Virtual Actors: ハッシュ計算による分散協調で SPOF を排除 結論 CQRS/ES の本質的な課題(競合制御)を解決するに は、アクターモデルによる「状態の局所化」と「単 一アクター保証」が必要

Slide 22

Slide 22 text

ご清聴ありがとうございました 質問・フィードバックはお気軽にどうぞ @j5ik2o @j5ik2o

Slide 23

Slide 23 text

No content