关于 arch-event-sourcing
面向评估事件溯源的开发者的架构指南,说明如何以仅追加的事件日志作为事实来源,并介绍重放、快照、版本管理和运维考量。
主要功能
- 01仅追加事件日志
- 02通过事件重放恢复状态
- 03使用快照加速读取
- 04事件模式演进
- 05与 CQRS 配合
适用场景
- 01保留审计历史
- 02查询过去某时点的状态
- 03生成多个读取模型
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ yonatankarp/ software-design-skills --skill arch-event-sourcing安装后在 Claude Code 中输入/arch-event-sourcing确认已加载。
详细介绍
一句话总结
将状态变更事件序列持久化为唯一事实来源。当前状态通过重放事件得出。事件日志仅追加、不可变且具有权威性。
何时使用此技能
- 需要完整变更历史的审计或监管要求。
- 业务确实以“发生了什么”的方式思考问题(银行交易、理赔调整、供应链事件)。
- 需要回答时间查询(“日期 X 的状态是什么”)。
- 需要同一数据的多个投影,且从事件物化比手动维护更容易。
- 与 CQRS 配合自然(参见
arch-cqrs),适用于读取需要不同于规范事件流的数据形态的情况。
何时不使用此技能
- 领域并不以事件为思维方式——强行将模型改造成事件形态,成本会超过收益。
- 当前状态已足够,且很少查询历史——CRUD 更简单。
- 团队不熟悉最终一致性、重放语义或事件版本管理——运维难题会非常严重。
- 因为微服务正流行,而且我们在哪里读到过“事件溯源”就想采用——这不是理由。
核心内容
事件存储。 仅追加的事件日志,每个事件都带有聚合 ID、序列号和时间戳。写入操作为 append(events);读取特定聚合的操作为 eventsFor(aggregateId)。
重建状态。 聚合的当前状态是对其事件进行折叠的结果:
state = events.fold(initial) { acc, event -> apply(acc, event) }
处理新命令时:加载事件,重放以获取当前状态,执行命令,然后追加新事件。内存中的状态是临时的;磁盘上的事件才是真相。
快照。 对于生命周期较长的聚合(包含数年事件),从头重放会变慢。快照是定期保存的事件 N 时的状态。加载时使用快照以及 N 之后的事件。快照是一种优化,不是唯一事实来源——事件仍然才是事实来源。
事件版本管理。 事件会永久保留。其架构必须向前兼容地演进。策略:
- 仅做增量变更——新增字段应为可选字段,绝不能设为必填。
- 升级器——在读取时将旧版本事件转换为当前形态的代码。
- 宽松架构(使用宽容解析的 JSON)——以编译时安全性为代价换取灵活性。
与 CQRS 配合。 事件溯源写入会自然地产生用于投影到读取模型的事件。大多数生产环境中的事件溯源系统会在查询中使用 CQRS,因为直接查询事件流并不方便。
运维注意事项。
- 事件存储的可用性至关重要——它是唯一事实来源。
- 工具(重放、重建投影、架构迁移)必须在做出承诺之前就已具备;项目中途才构建这些工具会很痛苦。
- 存储量会单调增长。应提前规划。
- 不带快照且包含数百万个事件的聚合将难以处理。
决策启发
- 对确实需要审计、时间查询或多个投影的聚合采用事件溯源。不要一概采用。
- 快照间隔是一个调节参数——从 100-500 个事件开始,根据重放性能进行调整。
- 将事件架构视为公共 API——为其添加版本;绝不要破坏它们。
- 在生产环境依赖事件溯源之前,先构建运维工具集(重放、重建、迁移)。
反模式
- 不加思考地对整个系统采用事件溯源。 大多数子域并不需要。应选择性应用——通常只用于有强烈审计需求的核心领域。
- 可变事件。 编辑过去的事件来“修正”历史。这会破坏整个模式。要“更正”,应追加一个补偿事件。
- 将事件当作 DTO。 事件除了表示“字段已更改”外没有任何语义含义。事件应是领域事件:使用过去时态,并具有业务意义。
- 在热点聚合上不使用快照进行重放。 每条命令都需要数秒,甚至数十秒。
- 架构变更时不使用升级器。 旧事件将无法读取。实际上,历史记录就此丢失。
另请参阅
arch-cqrs— 从事件投影读取模型。arch-event-driven— 将事件作为跨上下文通信(通常使用相同的事件)。ddd-domain-event— 战术层面的事件概念。ddd-aggregate— 事件溯源聚合在处理命令时生成事件。
参考资料
- Khononov,Learning DDD,第 7 章(事件溯源领域模型)。
- Vaughn Vernon,Implementing Domain-Driven Design — 第 8 章提供了经典的 Java 讲解。
- Greg Young,关于事件溯源的演讲和文章(奠基性资料)。
评论
支持 Markdown