手册
分散システムにおける CQRS (コマンド クエリ責任分離): イベント、ブローカー、プロジェクション (CQRS 2)
CQRS は分散システムでどのように機能しますか?ドメイン イベント、メッセージ ブローカー、プロジェクション、送信ボックス、冪等性、および最終的な整合性の決定をエンドツーエンドで検査します。
CQRS (コマンド クエリ責任分離) — 意思決定の構造
部分 3 的 4
The problem we are solving first
An order has been created. Inventory must know, notifications must send an email, analytics must prepare a report, and search must index the new order.
Order Service
→ HTTP call for Inventory
→ HTTP call for Notifications
→ HTTP call for Analytics
→ HTTP call for Search
Should the Order Service call each of them over HTTP? Every new capability expands the call chain, failure surface, and pressure to deploy together. No. The Order Service should share the business fact that happened; how it is used belongs to each consumer.
CQRS の最初の 2 つの部分では、リクエストがコマンド側とクエリ側でどのように処理されるかを分けました。分散システムにおける新たな問題は、注文が受け入れられた後、在庫、通知、分析、検索チームはどのようにしてこの変更を安全に知ることができるのかということです。text POST /orders → Command Handler → OrderPlaced olayı → Outbox → Relay → Message Broker ├─ Inventory projection ├─ Notification consumer ├─ Analytics projection └─ Search read model イベントは実際のビジネス上の不変の事実です。 OrderPlaced は意図したものではなく、起こった事実です。 ブローカー はイベントをプロデューサーからコンシューマーに移動します。 コンシューマ は、自らの責任でイベントを処理します。 投影は、イベント ストリームからの読み取りに適したビューを生成します。
最初に説明した概念```text
📦 Domain event Geçmiş zamanda ifade edilen, iş alanında gerçekleşmiş değişmez bir gerçektir.
📦 Broker Mesajı kalıcılaştıran ve tüketicilere dağıtan iletişim katmanıdır.
📦 Projection Event'lerden belirli bir ekran veya sorgu için üretilen read modeldir.
📦 Idempotency
Aynı event iki kez gelirse sonucu ikinci kez değiştirmeme özelliğidir.
```コマンドには PlaceOrder と表示されます。システムに動作を要求します。成功すると、OrderPlaced を公開できます。コマンドは拒否される可能性があります。出来事はもう変えることができない事実です。
ブローカーの配信は、少なくとも 1 回 であることが多く、同じメッセージが再度表示される可能性があります。したがって、コンシューマは、メッセージ ID を隠すか、本質的に冪等になるようにトランザクションを設計することによって、重複を安全に処理する必要があります。```text if processedEvents.contains(event.id): return
applyProjection(event) markProcessed(event.id)
## Why the design looks this way
~~~text
PlaceOrder → an intent.
OrderPlaced → a fact that happened.
~~~
We make this distinction **because** a command can fail, while an event is a completed fact other systems can safely react to.
- **Outbox** is needed **because** the broker and database do not share one ACID transaction.
- A **projection** is needed **because** an admin panel, mobile app, dashboard, and analytics need the same order in different shapes without loading the aggregate.
- **Idempotency** is needed **because** a broker can redeliver the same message for reliable delivery.
- A **saga** is needed **because** inventory must not remain reserved forever when payment fails in e-commerce.
- Most applications that use CQRS do not use Event Sourcing; they are independent decisions.
## 単一サービスの制限を超えると何が変化しますか?
単一のアプリケーションで、トランザクション、データ記録、副作用を同じプロセスで管理できます。システムが分散されると、インベントリ、電子メール、レポートには独自のライフサイクルが発生します。サービスが別のサービスに対して同期 HTTP 呼び出しを行うことは、短期的には簡単に思えます。ただし、呼び出しごとに、待ち時間、エラーの伝播、および共同デプロイのプレッシャーが追加されます。
イベントベースのフローは、この依存関係をデータ コントラクトに移動します。順序付けサービスは、`OrderPlaced` イベントのスキーマを担当します。ストック サービスは、必要な部分のみを消費します。プロデューサはコンシューマのデータベースやランタイムを知りません。独立した展開可能性は、独立した可観測性がなければ、単にリスクを置き換えるだけです。
## トランザクション境界からイベントを安全に削除する
単純なフローは次のとおりです。```text
Save order
→ Commit
→ Publish OrderPlaced
```コミットは成功したがパブリッシュが失敗した場合、システムは順序を認識しますが、他のサービスは認識しません。パブリッシュとコミットを逆の順序で行わないと、ゴースト イベントが発生します。 **送信ボックス パターン** では、同じローカル トランザクションに 2 つの書き込みが行われます。```text
Transaction
→ Order kaydını yaz
→ Outbox'a OrderPlaced kaydını yaz
→ Commit
Relay
→ Outbox kaydını broker'a ilet
→ teslim edildi olarak işaretle
```Outbox は分散トランザクションを確立しません。これにより、データベースに注文がある場合、発行されるイベントが存在するという重要な事実が保証されます。リレーは再試行する可能性があります。したがって、消費者側で冪等性の必要性が消えるわけではありません。
**CDC** はデータベース ログから変更をキャプチャできます。 CDC は、既存のデータベースに変更を伝播するのに強力です。ただし、ドメイン言語の制御が制限される場合があります。一方、Outbox を使用すると、アプリケーションはどのイベントがビジネス上の意味を持つかを明確に選択できます。
|質問 | CDC |送信ボックス |
| --- | --- | --- |
|ドメイン言語によるイベントの選択 |限定 |クリアかつ完全 |
|アプリケーショントランザクションへのリンク |間接的 |ダイレクト |
|消費者の冪等性の必要性 |はい |はい |
## プロジェクション: コピーではなく、意図指向のビュー
読み取りモデルは、書き込みモデルの不完全なコピーではありません。商品リストの場合は`ProductSearchRow`、操作パネルの場合は`OrderFulfilmentSummary`が生成できます。同じイベントが、さまざまなチームのさまざまな予測に影響を与える可能性があります。```text
OrderPlaced
→ OrderSummaryProjection
→ { orderId, customerName, total, status }
OrderPlaced
→ InventoryProjection
→ { sku, reservedQuantity, availability }
```プロジェクションは再構築可能である必要があります。コードが変更されるかエラーが修正されると、イベント ストリームが制御された方法で再生され、新しい読み取りモデルが検証されます。このためには、イベントの順序、チェックポイント、バージョン管理、および再生速度を測定する必要があります。予測遅延は製品言語で表示される必要があります。ユーザーが注文してから数秒後にリストに表示されることは許容されますか?答えは技術的な決定ではなく、ビジネス上の決定です。
## ブローカーの選択はブランドの選択ではありません
ブローカー;ソート、永続化、コンシューマ グループ、リプレイ、エラー キューの保証を提供します。同じキーの順序が重要な場合は、パーティション キーを設計する必要があります。消費者が遅れる可能性がある場合は、遅れ、再試行、および配信不能戦略に従う必要があります。スキーマが変更されている場合は、古いフィールドを急いで削除しないで、新しいフィールドを追加します。イベントのバージョンは下位互換性を維持する必要があります。
## イベント ソーシングと CQRS は同じものではありません
CQRS は読み取りと書き込みの責任を分離します。一方、イベント ソーシングは、現在の行ではなく追加専用のイベント ストリームから集約状態を生成します。これらは一緒に使用できます。ただし、イベント ソーシングは CQRS には必須ではなく、Kafka はイベント ソーシングには必須ではありません。イベント ソーシングが選択されている場合、スナップショット、ストリーム バージョン、および再生コストは個別に設計されます。
## 佐賀: 分散ワークフローにおける報酬決定
注文は支払い、在庫、発送のステップを経る場合があります。これらの手順は、単一の ACID トランザクションに収まりません。 Saga は、ローカル操作ごとに補償ステップを定義します。```text
Order placed
→ reserve inventory
→ capture payment
→ create shipment
payment fails
→ release inventory
→ mark order failed
```**Choreography** では、サービスがイベントによって相互にトリガーできるようになります。ローカル依存性は低いですが、全体の流れを追うのが難しくなります。 **オーケストレーション** により、中央プロセス マネージャーでフローが可視化されます。ひいては、調整の責任も加わります。
## 運用チェックリスト
1. 各イベントの名前は過去形およびビジネス用語で付けられていますか?
2. Outbox はデータベースの記録とイベントの発行の間のギャップを埋めますか?
3. コンシューマーの重複、キューの破損、遅延イベントに対して安全ですか?
4. 投影チェックポイント、ラグ、および再構築手順を観察できますか?
5. イベント契約の所有者、リリース戦略、下位互換性ルールは明確ですか?
6. 最終整合性ウィンドウはユーザーに表示され、製品によって受け入れられますか?
これらの質問に答えられない場合、システムはイベント駆動型であるように見えます。しかし、失敗主導で行動します。
## 混同されやすい区別```text
❌ Event = Command
✓ Command niyettir; event gerçekleşmiş gerçektir.
❌ Broker = Event Store
✓ Broker event'i taşır; Event Store domain geçmişinin kalıcı kaynağı olabilir.
❌ Projection = cache
✓ Cache hız için geçicidir; projection iş sorgusu için bilinçli bir read modeldir.
❌ At-least-once = hata
✓ Tekrar teslimat normaldir; consumer idempotent olmalıdır.
```## 真のエンドツーエンド ストリーミング```text
POST /orders
→ Controller
→ Mediator.Send()
→ Validation + Authorization
→ Transaction Behavior
→ PlaceOrderHandler
→ Order aggregate
→ Order + Outbox commit
→ Relay
→ Broker
→ Projection consumer
→ Read database
→ GET /orders
→ Query Handler
→ OrderSummaryDto
→ Frontend
このモデルはいつ使用する必要がありますか?
まず論理 CQRS から始めます。コマンドにビジネス言語で名前を付け、クエリを画面に必要なものに減らし、トランザクションの境界を明確にします。ブローカーと個別のプロジェクションは、独立したコンシューマー、非対称読み取りロード、または再生可能な統合の必要性が証明された場合にのみ追加する必要があります。
新しいコンシューマごとのコストは O(1) コード変更のように見えるかもしれませんが、運用コストは固定されていません。契約、ダッシュボード、アラーム、再試行、所有権、およびテスト シナリオが必要です。
反省
分散型 CQRS で期待されるのは、メッセージが増えることではなく、責任がより目に見えるようになることです。イベントは履歴を運び、ブローカーはフローを運び、プロジェクションはユーザーに見える結果を運びます。
イベント ストリームは、再度到着する場合、遅れて到着する場合、および再生される場合に安全である場合にのみ、アーキテクチャ上の決定となります。
次のセクションでは、システムの実行中にクラッシュが発生した場合に、一貫性、重複、プロジェクションの破損、回復戦略などの変化について見ていきます。
What should remain with you?
If you remember only five things:
- A command requests behavior.
- An event is a fact that happened.
- A broker carries events to the right consumers.
- A projection reads the same fact in the shape each screen needs.
- Outbox prevents event loss because the broker and database do not share one ACID transaction.
Every separation in this chapter has a reason: idempotency is needed because a broker can redeliver; a projection is needed because querying an aggregate for every screen is expensive and the wrong abstraction.
FAQ
Frequently asked questions
ドメインイベントとは何ですか?
過去形で表現すると、ビジネスの現場で起きた不変の事実です。
ブローカーとは何ですか?
メッセージを永続化し、消費者に配布するのは通信層です。
「イベント=コマンド」は正しいでしょうか?
命令は意図です。その出来事は本物です。
学到的工程原理
- 分散システムでは、イベントはコマンドではありません。これは確立された不変のビジネス上の事実です。
- 少なくとも 1 回の配信に相当するのは冪等のコンシューマです。重複メッセージは設計上の入力であり、例外ではありません。
- 投影は再構築可能かつ測定可能でなければならず、その遅延は製品言語で定義されなければなりません。
继续阅读
继续阅读
系列中的下一个
本番環境における CQRS (コマンド クエリ責任分離): 一貫性、エラー、および回復戦略
CQRS は実稼働環境でどのように安全に機能しますか?一貫性の遅れ、イベントの重複、シーケンスの破損、投影の回復、再試行、DLQ および Saga 戦略。
系列中的下一个
CQRS (コマンドクエリ責任分離) パイプラインはどのように機能しますか?コマンドとクエリのフローの構造
CQRS リクエスト パイプラインとは何ですか? HTTP リクエストは、コントローラー、MediatR、パイプライン動作、ハンドラー、送信ボックス、読み取りモデルをどのように通過するのでしょうか?
同系列
CRUD (作成、読み取り、更新、削除) から CQRS (コマンド クエリ責任分離) まで: 問題はコードではなくモデルです
CQRS とは何ですか? CRUD と CQRS の違いは何ですか? CQRS はどのような場合に使用する必要がありますか?大規模システムでは単一モデルでは不十分な理由を説明するガイド。