2. 事件驱动架构基础:事件、命令、消息、事件溯源与CQRS模式概述
在构建具备自愈能力的分布式系统时,事件驱动架构(EDA)是核心的通信与数据管理范式。本章将厘清四个基础概念——事件、命令、消息,并深入探讨事件溯源(Event Sourcing)与CQRS(命令查询职责分离)模式,为后续的补偿机制与熔断降级策略奠定理论基础。
2.1 核心概念辨析:事件、命令与消息
在分布式系统中,这三者常被混用,但它们在语义和用途上有本质区别。理解这些差异是设计正确补偿逻辑的前提。
| 概念 | 语义 | 发起者 | 预期响应 | 典型用途 |
|---|---|---|---|---|
| 事件(Event) | “某事已经发生” | 事件生产者 | 无(广播通知) | 状态变更通知、审计日志、触发下游补偿 |
| 命令(Command) | “请执行某个操作” | 命令发起者 | 期望一个结果(成功/失败) | 业务操作请求、状态变更指令 |
| 消息(Message) | “这是一段数据” | 发送方 | 取决于协议(点对点/发布订阅) | 通用数据传输、RPC调用、异步通信 |
关键区分:命令是“意图”,事件是“事实”。在自愈剧本中,补偿动作通常由“事件”触发,而非“命令”。例如,“订单已取消”事件触发“库存回滚”补偿,而不是直接发送“回滚库存”命令。
2.2 事件溯源(Event Sourcing)
事件溯源是一种数据持久化模式,其核心思想是:不存储系统的当前状态,而是存储导致状态变化的所有事件序列。系统当前状态可以通过重放所有历史事件来推导。
- 优势:提供完整的审计轨迹、支持时间旅行调试、天然支持补偿(通过发布“反向事件”)。
- 挑战:事件模式演进困难、查询当前状态需要聚合重放、存储量随时间增长。
- 与补偿的关系:补偿机制在事件溯源中表现为发布一个“补偿事件”,该事件会修正之前错误事件的影响。
实战案例:在电商系统中,一个“订单已支付”事件(Event)被持久化。如果后续支付网关返回失败,系统不会删除该事件,而是追加一个“支付已撤销”事件。重放事件序列时,系统会正确推导出订单的最终状态为“未支付”。
2.3 CQRS(命令查询职责分离)
CQRS 是一种将系统的读操作(查询)与写操作(命令)分离到不同模型中的架构模式。它通常与事件溯源配合使用,但并非必须。
- 写模型(Command Model):处理命令,验证业务规则,生成事件。通常使用事件溯源存储。
- 读模型(Query Model):处理查询,返回优化后的视图。可以是关系型数据库、缓存、搜索引擎等。
- 同步机制:写模型生成的事件通过事件总线异步更新读模型。
注意:CQRS 增加了系统复杂度。对于简单的 CRUD 应用,引入 CQRS 可能得不偿失。它最适合高并发读写、复杂业务逻辑或需要不同查询视图的场景。
2.4 事件驱动架构核心流程
下图展示了事件驱动架构中,命令、事件、事件溯源与 CQRS 如何协同工作。一个典型的流程是:客户端发送命令 → 命令处理器验证并生成事件 → 事件存储持久化 → 事件发布到总线 → 读模型订阅并更新视图。
2.5 事件溯源与CQRS的协同关系
事件溯源和 CQRS 是天然的搭档,但并非绑定关系。下表总结了它们的组合方式及适用场景。
| 组合模式 | 写模型 | 读模型 | 典型场景 |
|---|---|---|---|
| 纯事件溯源 | 事件存储 | 通过重放事件推导 | 审计、合规、金融交易 |
| 事件溯源 + CQRS | 事件存储 | 独立优化的视图 | 电商、社交、高并发查询 |
| 纯CQRS | 传统数据库 | 独立优化的视图 | 读写分离、报表系统 |
2.6 事件驱动架构中的补偿触发点
在自愈剧本中,补偿机制的触发通常依赖于事件溯源提供的历史事件和 CQRS 提供的实时视图。下图展示了补偿事件如何被注入到事件流中。
2.7 本章小结
- 事件是“已发生的事实”,命令是“期望的操作”,消息是“数据传输载体”。
- 事件溯源通过持久化事件序列来记录系统状态变化,为补偿提供了天然的“撤销”机制。
- CQRS 分离读写模型,优化查询性能,常与事件溯源配合使用。
- 在自愈剧本中,补偿机制通过发布补偿事件来修正错误,这些事件被追加到事件流中,确保系统状态的一致性和可审计性。