Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CQRS/ESになぜアクターモデルが必要なのか

 CQRS/ESになぜアクターモデルが必要なのか

この問いは、CQRS/ESを触った人なら一度は悩むポイントです。

CQRS/ES のコマンド側をオブジェクトモデルで実装することは可能です。
しかし、イベント書き込み時のロック競合、同時更新の制御、分散環境での一貫性維持といった課題に直面します。
これらを根本的に解決する仕組みが「アクターモデル」です。
集約をアクターとして実装し、クラスタシャーディングによって「1集約=1実体」を保証すれば、
ロックレスかつ逐次的に状態を管理できます。
さらにメッセージ駆動により時間・場所・障害からの分離が得られ、
リアクティブシステムとしてスケールと耐障害性を自然に実現できます。

なぜコマンド側にアクターモデルが適しているのかを、Pekko/Akka を題材に深堀りして解説します。

Avatar for かとじゅん

かとじゅん

January 09, 2026
Tweet

More Decks by かとじゅん

Other Decks in Technology

Transcript

  1. プロフィール 加藤潤一 経歴 10 歳からプログラミング開 始 〜2011: SIer+Java+ 金融 2011

    〜2014 年: ドワンゴ, グ リー 2014 〜2024 年: kubell (旧 Chatwork ) 2025 年1 月〜 IDEO PLUS 社 専門分野 ドメイン駆動設計(DDD ) 関数型プログラミング 分散システム設計 15 年以上のDDD 実践経験 | Chatwork の大規模リアーキテクチャを主導 分散システム・スケーラブルアーキテクチャのエキスパート(LAPRAS 調べ)
  2. 本日のアジェンダ # トピック 内容 1 オブジェクトベースCQRS/ES の限界 イベント追い越し問題と楽観的ロックの課題 2 アクターモデルの基礎と解決策

    Share Nothing ・逐次処理・SSoT によるロック不要化 3 クラスタリングとVirtual Actors SPOF の課題と分散協調による解決 ゴール: CQRS/ES におけるアクターモデルの必然性を理解する
  3. ロック機構がない場合の「イベント追い越し・不整合」 前提: 楽観的ロック(バージョンチェック)がな い素朴な実装 シナリオ: 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 で上書き発⽣)
  4. スライド案:解決策としての楽観的ロック(しかし… ) 解決策: バージョンによる楽観的ロック 仕組み: 書き込み時に「読み込んだ時のバージョ ン(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)
  5. アクターモデルとは 基本概念(Carl Hewitt, 1973 ) アクター: 計算の基本単位。状態・振る舞い・メ ールボックスを持つ メッセージパッシング: アクター間の唯一の通信

    手段 逐次処理: 各アクターは一度に1 つのメッセージ のみ処理 アクターができること 1. メッセージを送る: 他のアクターにメッセージを 送信 2. 新しいアクターを作る: 子アクターを生成 3. 自身の状態を変える: 次のメッセージへの振る舞 いを決定
  6. アクターによってドメイン状態をシステムに取り戻す システム全体において、そのアクターは一つしか 存在しないため、イベントの追記のためにロッ クが不要になる DB には状態はなくイベントログしか書かれな い。インピーダンスミスマッチの解消も不要( イ ンピーダンスミスマッチの解消はRead Model

    Updater が担う) 状態はアクター内部のオブジェクトが持つ。状態 の近くでなければドメインリッチにはならない そして アクターが信頼できる唯一の情報源 =SSoT になる ただし、アクターのクラスターとシャー ディングの機構が必要になる
  7. Akka/Pekko Cluster(2009-) Akka (Scala/Java), Pekko (Scala/Java) Shard Coordinator: 各シャー ドの担当ノードを管理

    Shard Region: シャードの管 理とリクエストのルーティン グを行う Shard Actor: エンティティア クターが所属するアクター Entity Actor: 集約のためのア クター
  8. ProtoActor Go (2022-) 意外に最近 Orleans のVirtual Actor を実 装している Grain

    はシャーディングされ たアクター Cluster Provider はetcd, Consul など
  9. まとめ 1. オブジェクトベースCQRS/ES の限界 ステートレスサーバーでイベントの追い越しが発 生 楽観的ロックで整合性は守れるが、リトライ負 担とUX 低下 2.

    アクターモデルによる解決 Share Nothing + メッセージパッシングでロック 不要 逐次処理保証でアクター内は常にシングルスレッ ド アクターが SSoT (信頼できる唯一の情報源) に 3. クラスタリングの課題と解決 Akka/Pekko: Shard Coordinator がボトルネック になりやすい Virtual Actors: ハッシュ計算による分散協調で SPOF を排除 結論 CQRS/ES の本質的な課題(競合制御)を解決するに は、アクターモデルによる「状態の局所化」と「単 一アクター保証」が必要