リファレンスアーキテクチャ: イベント駆動 / CQRS
イベント駆動アーキテクチャでは、サービスは互いを直接呼び出す代わりにイベントログ (例: Kafka) にイベントを発行し、コンシューマーがそれを非同期に処理する。このツリーは、イベント基盤の構築を起点に、イベントソーシング (イベントから状態を導出)、CQRS によるコマンド/クエリの分離、読み取りモデルのプロジェクション、冪等性、結果整合性の許容、「exactly-once 配信」の誤謬を段階的に説明する。目的は、一貫性のトレードオフがよく理解された、疎結合でスケーラブルなシステム。
イベント駆動アーキテクチャでどの判断に直面しているか?
イベント駆動システムの基盤は、非同期のイベントでサービスを結び付ける永続的なイベントログ。まだ基盤を構築している段階か、イベントから状態を導出したい (イベントソーシング) のか、それとも読み取りと書き込みの経路を分離している (CQRS) のか?
- サービスを結び付けるイベント基盤を構築している
- イベント履歴から状態を導出したい
- 読み取りと書き込みの経路を分離したい (CQRS)
CQRS で読み取り側をどう構築するか、また一貫性の許容度は?
CQRS では、コマンド (書き込み) 側とクエリ (読み取り) 側が分離され、書き込みイベントが読み取りモデルに供給するプロジェクションを更新する。重要な問い: 読み取りモデルが書き込みより遅れること (結果整合性) を許容できるか、それともすべてのイベントが正確に 1 回だけ処理されることを期待するか?
- プロジェクションを介してイベントから読み取りモデルに供給する
- 読み取りは最新でなければならない。遅延は許容できない
- イベントを「正確に 1 回」処理したい
推奨: 永続的なイベントログ基盤
イベント駆動アーキテクチャの中心には、プロデューサーが書き込み、コンシューマーが自分のペースで読み取る、永続的で順序付けられたイベントログがある。この基盤がサービスを時間とスケールの面で切り離す。
推奨: イベントソーシング (イベントから状態を導出)
イベントソーシングでは、エンティティの現在の状態ではなく、それに適用されたすべての (不変の) 変更イベントを保存する。現在の状態は、これらのイベントを順に適用して導出する。完全な監査履歴と、過去の任意の時点に戻る機能を提供する。
推奨: 読み取りモデルのプロジェクション
CQRS では書き込み側がイベントを生成し、プロジェクションがこれらのイベントを受信して、クエリに最適化された読み取りモデル (非正規化ビュー) を更新する。読み取りはこの準備済みモデルから提供され、書き込み経路から完全に分離されるため、両側が独立してスケールする。
推奨: 結果整合性を許容する設計
イベント駆動/CQRS システムでは、読み取りモデルは書き込みよりわずかに遅れる (結果整合性)。これを「排除」しようとするのではなく、許容するよう設計する。厳密な即時一貫性が必要な少数のフローは分離しておく。
推奨: 冪等性 (exactly-once の誤謬)
分散メッセージングでは、エンドツーエンドの「exactly-once 配信」は実際には誤謬であり、ネットワークとリトライのためメッセージの重複は避けられない。正しい目標は冪等な処理: 同じイベントを 2 回処理しても、1 回処理した場合と同じ結果になること。