Chuyển đến nội dung chính

レッスン 9: イベント ソーシングと CQRS — いつ必要で、いつ必要でしょうか?

イベント ソーシング: 状態の代わりにイベントを保存します。 CQRS: 個別の読み取り/書き込みモデル。イベント ソーシングと CQRS を組み合わせます。トレードオフ、複雑さ、意思決定の枠組み。 CQRS が複雑すぎるのはどのような場合でしょうか。また、CQRS が本当に必要なのはどのような場合でしょうか?

🏗️ アーキテクチャ — レッスン 9 レッスン 9: イベント ソーシングと CQRS — いつ 必要なとき、必要ないときは?

マイクロサービスとマイクロ フロントエンドのシステム設計 — 基本から運用まで

パート 3: マイクロサービスのデータ アーキテクチャ

xdev.asia

はじめに

イベント ソーシングと CQRS は 2 つの強力なパターンですが、悪用されることが多い パターンです。この記事は、その性質、実際の利点、そして最も重要なことである 使用すべきではない場合 を理解するのに役立ちます。

CQRS とイベント ソーシング — 個別のコマンドとクエリ


1. イベントソーシング

1.1 中心となるアイデア

現在の状態を保存する代わりに、発生した一連のイベントを保存します。

Traditional (State-based):
┌─────────────────────────┐
│ orders table            │
│ id: 123                 │
│ status: SHIPPED   ← chỉ biết trạng thái hiện tại
│ total: 500.000         │
└─────────────────────────┘

Event Sourcing:
┌─────────────────────────────────────┐
│ Event Store (Order #123)            │
│ 1. OrderCreated    {items, total}   │
│ 2. PaymentReceived {amount}         │
│ 3. ItemRemoved     {itemId}   ← biết toàn bộ lịch sử
│ 4. OrderConfirmed  {}               │
│ 5. OrderShipped    {trackingId}     │
└─────────────────────────────────────┘

State = replay(events) → current state

1.2 利点

  • 完全な監査証跡: 誰がいつ何をしたかを正確に把握できます
  • タイムトラベル: いつでも状態を再構築できます
  • デバッグ: イベントをリプレイしてバグを再現します。
  • 分析: イベント パターンを分析します。

1.3 欠点

  • 複雑さ: イベント ストア、プロジェクション、スナップショットが必要
  • 結果整合性: 読み取りモデルはリアルタイムではありません
  • スキーマの進化: イベント スキーマの変更は非常に困難です
  • 難しいクエリ: ステータス = '発送済み' の注文から * を選択することはできません

2. CQRS (コマンドクエリ責任分離)

2.1 読み取りと書き込みの分離

Traditional:
┌──────────┐     ┌──────────┐
│  Client  │────►│ Service  │────► Database
│          │◄────│(CRUD all)│◄──── (1 model)
└──────────┘     └──────────┘

CQRS:
                 ┌──────────────┐     ┌────────────┐
           ────► │ Command Side │────►│ Write DB   │
┌──────────┐     │ (Create,     │     │ (optimized │
│  Client  │     │  Update)     │     │  for write)│
└──────────┘     └──────────────┘     └─────┬──────┘
           ────► ┌──────────────┐           │ Events
                 │ Query Side   │     ┌─────▼──────┐
           ◄──── │ (Read,       │◄────│ Read DB    │
                 │  Search)     │     │ (optimized │
                 └──────────────┘     │  for read) │
                                      └────────────┘

2.2 CQRS が価値があるのはどのような場合ですか?

  • 読み取り/書き込み比率 大きく異なります (読み取り 90%、書き込み 10%)
  • 読み取りモデルには 別の形式 書き込みモデルが必要です (非正規化ビュー)
  • 読み取り/書き込みを独立してスケーリングする必要がある(リードレプリカを追加する)
  • 複雑なクエリには 最適化された読み取りモデル が必要です (Elasticsearch、マテリアライズド ビュー)

3. 意思決定の枠組み

3.1 イベント ソーシング + CQRS をいつ使用するか?

✅ 金融システム (監査証跡が必要) ✅ 注文処理(複雑なステータス、ニーズ履歴) ✅ 共同編集 (競合の解決) ✅ 規制遵守(何が起こったかを証明する必要がある)

3.2 使用すべきでない場合は?

❌ 単純な CRUD (ブログ、ユーザー プロファイル) → やりすぎ ❌ チームが小さく、経験がない → 学習曲線が高すぎる ❌ 証跡やタイムトラベルを監査する必要はありません ❌ リアルタイムの一貫性が必要です

3.3 イベント ソーシングなしで CQRS を使用できる

CQRS without Event Sourcing (pragmatic approach):

Write Side: PostgreSQL (normalized)
  → On write: publish event to Kafka
  
Read Side: Elasticsearch (denormalized)
  → Consumer: listen events → update search index

Đơn giản hơn nhiều, vẫn có lợi ích tách read/write.

4. 電子商取引への申請

Product Service: CQRS (no Event Sourcing)
  Write: PostgreSQL (products table)
  Read:  Elasticsearch (search index, facets)
  Sync:  ProductUpdated event → ES consumer

Order Service: Event Sourcing + CQRS (trạng thái phức tạp)
  Event Store: PostgreSQL (events table)
  Read Model: PostgreSQL (materialized orders view)
  
Cart Service: Simple CRUD (Redis)
  Không cần CQRS — read/write model giống nhau

User Service: Simple CRUD (PostgreSQL)
  Không cần CQRS — straightforward CRUD

概要

パターン複雑さいつ使用するか避けるべき場合
シンプルな CRUD低いほとんどのサービス高トラフィックの読み取り
CQRS のみ中個別の読み取り/書き込みスケール単純なドメイン
イベントソーシング高監査証跡、タイムトラベルシンプルな CRUD
ES + CQRS非常に高い財務、発注その他ほぼすべて

黄金律: シンプル (CRUD) から始めてください。 CQRS/ES は、特定の問題点が必要であることが判明した場合にのみ追加してください。


次の記事: レッスン 10: マイクロ フロントエンドとは何ですか? — 利点、トレードオフ、意思決定の枠組み