# イベントソーシングとCQRS ## 定義 イベントソーシングとは、システムのすべての状態変化を*イベント*——過去形で名付けられたイミュータブルな事実(例:「座席が予約された」)——として順序付きの追記専用ログに記録し、このイベントログを唯一の真実の源(source of truth)とする設計スタイルである。CQRS(command query responsibility segregation、コマンドクエリ責務分離)は、この書き込み最適化されたイベントログから、読み取りに最適化された複数の*マテリアライズドビュー*(projection、read modelとも呼ばれる)を導出するという、書き込みと読み取りの表現を分離する原則である。両用語はDDD(ドメイン駆動設計)コミュニティに由来するが、同種の発想は分散システムにおける状態機械複製(state machine replication)など以前から存在した。ユーザーからのリクエストは*コマンド*と呼ばれ、検証され有効と判定されて初めて事実(イベント)としてログに追記される——イベントログには常に有効なイベントのみが含まれ、マテリアライズドビューを構築する消費者はイベントを拒否できない。(Source: [[@2026__OReilly__Designing Data-Intensive Applications 2E - Chapter 3 Data Models and Query Languages]] "Event Sourcing and CQRS") ## スター・スキーマのファクトテーブルとの異同 イベントソーシングは、過去に起きたイベントの集合という点で[[スター・スノーフレークスキーマ|スター・スキーマ]]のファクトテーブルと類似する。ただしファクトテーブルの各行は同じカラム集合を持つのに対し、イベントソーシングでは多様なイベント型がそれぞれ異なるプロパティを持ちうる。また、ファクトテーブルが順序を問わない集合であるのに対し、イベントソーシングではイベントの*順序*が本質的に重要である(予約とキャンセルを逆順に処理すると意味が壊れる)。(Source: [[@2026__OReilly__Designing Data-Intensive Applications 2E - Chapter 3 Data Models and Query Languages]] "Event Sourcing and CQRS") ## 利点 - **意図の伝達**: 「予約がキャンセルされた」というイベントは、行われる個々のテーブル更新の羅列より*なぜ*その変更が起きたかを明確に伝える。 - **再現可能性**: マテリアライズドビューはイベントログから決定的に再計算できるため、ビュー構築コードにバグがあってもビューを削除して再構築すればよく、デバッグも容易になる。 - **多様な読み取り最適化ビュー**: 同一のイベントログから、用途ごとに異なるデータモデル・異なるデータベース(あるいはメモリ上のみ)に最適化された複数のビューを導出できる。 - **evolvability**: 新しいイベント型やプロパティを追加しても既存イベントは変更不要で、新しいビューの追加も容易。 - **可逆性**: 誤って書かれたイベントは、取り消しイベントを追記することで下流ビューへ自動的に反映される(update/deleteを直接行うDBでは committed transaction の取り消しはしばしば困難)。 - **監査ログ**: イベントログは規制業界で要求される監査証跡としても機能する。 - **高い書き込みスループット**: 順次アクセスパターンのため、突発的な書き込みバーストを吸収し、下流のビュー構築は自分のペースで追いつける。 (Source: [[@2026__OReilly__Designing Data-Intensive Applications 2E - Chapter 3 Data Models and Query Languages]] "Event Sourcing and CQRS") ## 欠点 - **外部情報の非決定性**: イベント処理が為替レートのような外部の可変情報に依存すると、日を変えて再計算した際に異なる結果が出てしまう。イベント自体に値を埋め込むか、タイムスタンプ指定で常に同じ結果を返す仕組みが必要になる。 - **GDPR等の削除要求との緊張**: イベントの不変性(immutability)は、ユーザーが個人データの削除を要求する権利(GDPR等)と衝突する。ユーザー単位でログが分かれていれば単純に削除できるが、複数ユーザーにまたがるログでは、個人データをイベント外に格納する、あるいは削除可能な鍵で暗号化する*crypto-shredding*のような技法が必要になり、これも派生状態の再計算を難しくする。 - **外部副作用の再実行リスク**: マテリアライズドビューの再構築時に確認メールの再送のような外部可視な副作用が意図せず再実行されないよう注意が必要。 (Source: [[@2026__OReilly__Designing Data-Intensive Applications 2E - Chapter 3 Data Models and Query Languages]] "Event Sourcing and CQRS") ## 実装 イベントソーシングは任意のデータベース上に実装できるが、EventStoreDB・MartenDB(PostgreSQLベース)・Axon Frameworkのようにこのパターン専用に設計されたシステムも存在する。[[Apache Kafka]]のようなメッセージブローカーをイベントログとして使い、ストリームプロセッサでマテリアライズドビューを最新化する構成も一般的である。唯一の絶対要件は、すべてのマテリアライズドビューがログ中と*まったく同じ順序*でイベントを処理することを保証することであり、これは分散システムにおいて自明ではない。(Source: [[@2026__OReilly__Designing Data-Intensive Applications 2E - Chapter 3 Data Models and Query Languages]] "Event Sourcing and CQRS") ## 横断的知見 - **同一書籍内で、第3章のイベントソーシングと第12章の変更データキャプチャ(CDC)は「変更のログ」という同じ発想を異なる抽象レベルで適用する対概念として並置される**: 第3章はイベントソーシングを、アプリケーションロジック自体を不変イベントの上に明示的に構築する設計スタイルとして導入する。[[@2026__OReilly__Designing Data-Intensive Applications 2E - Chapter 12 Stream Processing]] "CDC versus event sourcing" 節はこれを CDC(→ [[変更データキャプチャ(CDC)]])と対比し、CDC がデータベースを可変な方法で使い続けたまま低レベルで(レプリケーションログの解析等により)変更を抽出するのに対し、イベントソーシングは高レベルで(ユーザーアクションの意図として)イベントを設計する点が本質的な違いだと整理する。ログコンパクションの可否もこの抽象レベルの違いから帰結する: CDC の更新イベントは通常レコードの新バージョン全体を含むため最新イベントのみ残せばよいが、イベントソーシングのイベントは互いを上書きしないため全履歴の保持が前提になる——第3章が単体で述べていた「イベントログからの決定的な再計算」という利点(→ 横断的知見の既存項目、[[導出データ]]参照)は、CDC と比べたときに「なぜイベントソーシングは全履歴保持を要求するのか」という設計上の理由まで説明される。(Source: [[@2026__OReilly__Designing Data-Intensive Applications 2E - Chapter 3 Data Models and Query Languages]] "Event Sourcing and CQRS", [[@2026__OReilly__Designing Data-Intensive Applications 2E - Chapter 12 Stream Processing]] "CDC versus event sourcing") - **第3章が「唯一の絶対要件」とだけ述べた順序保証の実現手段を、第12章がログベースメッセージブローカとして具体化する**: 第3章は「すべてのマテリアライズドビューがログ中とまったく同じ順序でイベントを処理することを保証する」ことを唯一の絶対要件と述べるにとどめ、これがどう実現されるかには立ち入らなかった(→ 既存の未解決の問い)。第12章は log-based message broker(→ [[分散メッセージブローカ]])のパーティション内単調増加オフセットが、この順序保証を実装レベルで提供する具体的な機構であることを示す——ただし保証されるのはパーティション内のみであり、複数パーティションにまたがる順序が必要なら同一のパーティションキー(例: ユーザーID)へルーティングする設計が必要になる。(Source: [[@2026__OReilly__Designing Data-Intensive Applications 2E - Chapter 3 Data Models and Query Languages]] "Event Sourcing and CQRS", [[@2026__OReilly__Designing Data-Intensive Applications 2E - Chapter 12 Stream Processing]] "Using logs for message storage") ## 未解決の問い - イベントログの「すべてのビューが同一順序でイベントを処理する」という要件は、分散合意やハイブリッド論理クロックといった分散システムのトピック(本書第10章)とどう具体的に結びつくか。**(部分的に解決)** 第12章により、ログベースメッセージブローカのパーティション内オフセットが順序保証の実装機構であることは判明したが、パーティションをまたぐ順序保証と分散合意の関係は依然として未検証。 - crypto-shreddingによるGDPR対応は、派生ビューの再計算可能性(reproducibility)という利点とどこまで両立するか。鍵削除後に再計算したビューは、鍵削除前のビューと整合するのか。 - ファクトテーブル(スター・スキーマ)とイベントログは類似する構造を持つが、実務ではどちらを選ぶかの判断基準(分析用途かオペレーション用途か)はどの程度明確に文献化されているか。 - CDC は既存データベースへ最小限の変更で導入できるのに対し、イベントソーシングはアプリケーション設計への大きな変更を要すると第12章は述べる。この「導入コストの非対称性」を踏まえ、既にCDCを運用しているシステムを段階的にイベントソーシングへ移行する現実的な経路は存在するか。 ## 関連 - ソース: [[@2026__OReilly__Designing Data-Intensive Applications 2E - Chapter 3 Data Models and Query Languages]] / [[@2026__OReilly__Designing Data-Intensive Applications 2E - Chapter 12 Stream Processing]] - 実体: [[Apache Kafka]] - 概念: [[導出データ]] / [[スター・スノーフレークスキーマ]] / [[変更データキャプチャ(CDC)]] / [[分散メッセージブローカ]] ## 出典 - [[@2026__OReilly__Designing Data-Intensive Applications 2E - Chapter 3 Data Models and Query Languages]]("Event Sourcing and CQRS") - [[@2026__OReilly__Designing Data-Intensive Applications 2E - Chapter 12 Stream Processing]]("CDC versus event sourcing", "Using logs for message storage")