每次我们在数据库中运行 UPDATE 语句,某些东西就消失了。旧值,无论刚才在那里的是什么,都消失了。
事实上,大多数数据库设计为忘记。每个 UPDATE 覆盖之前的内容,每个 DELETE 完全移除它,应用只剩下当前状态的快照。我们接受这是正常的,因为这是最自然的思考方式。
但如果你的系统需要回答不同类型的问题:不仅是”当前状态是什么?“而是”我们如何到达这里?”
这就是事件溯源构建来回答的问题。解决方案既比它首先出现的更有回报也更有要求。在本文中,我们将看看事件溯源以及它的好处和权衡。
问题
传统数据库方法有根本限制。当你运行 UPDATE 时,旧值消失。当你运行 DELETE 时,它完全移除。你只剩下当前状态的快照。
这对许多应用工作良好。但有些场景需要知道历史:
- 审计要求:谁在什么时候改变了什么?
- 调试:系统如何到达这个状态?
- 合规性:需要完整的历史记录
- 业务分析:理解模式和趋势
事件溯源解决方案
事件溯源通过存储事件序列而不是当前状态来解决这个问题。
核心概念
不是更新当前状态,每个变化作为事件存储:
初始状态:账户余额 = $100事件 1:存款 $50事件 2:取款 $30事件 3:存款 $20当前状态:$140(通过重放事件计算)工作原理
- 事件捕获:每个状态变化作为不可变事件存储
- 事件存储:事件按时间顺序存储在事件存储中
- 状态重建:当前状态通过重放所有事件计算
- 快照:定期创建快照以优化重建性能
好处
1. 完整审计跟踪
- 每个变化都记录
- 知道谁在什么时候做了什么
- 满足合规要求
2. 时间旅行
- 可以重建任何时间点的状态
- 调试历史问题
- 分析历史趋势
3. 灵活性
- 可以添加新的读取模型
- 可以从相同事件派生不同视图
- 容易适应新需求
4. 可追溯性
- 理解系统如何到达当前状态
- 调试更容易
- 业务洞察更丰富
权衡
1. 复杂性
- 更复杂的架构
- 需要事件版本控制
- 查询更复杂
2. 性能
- 状态重建可能慢
- 需要快照优化
- 存储更多数据
3. 学习曲线
- 团队需要学习新模式
- 思维模式转变
- 工具链不同
4. 事件模式演化
- 事件模式变化困难
- 需要向后兼容
- 可能需要事件升级
用例
适合事件溯源的场景
金融系统
- 需要完整审计跟踪
- 合规要求严格
- 需要时间旅行
电商订单系统
- 订单状态变化复杂
- 需要追溯订单历史
- 需要分析购买模式
库存管理
- 需要跟踪库存变化
- 需要审计库存调整
- 需要预测趋势
工作流系统
- 复杂的状态机
- 需要审计工作流
- 需要重放事件
不适合事件溯源的场景
简单 CRUD 应用
- 不需要历史
- 简单读写模式
- 性能要求高
实时性要求极高
- 状态重建太慢
- 需要即时响应
- 缓存更有效
数据量巨大
- 事件存储过大
- 重建成本太高
- 快照管理复杂
实施考虑
1. 事件设计
- 使用过去时态命名(OrderCreated、PaymentProcessed)
- 包含所有相关信息
- 保持事件不可变
- 考虑事件版本控制
2. 事件存储
- 选择合适的事件存储
- 考虑事件追加性能
- 实现快照策略
- 规划事件归档
3. 查询优化
- 构建读取模型(CQRS)
- 使用投影优化查询
- 实现缓存策略
- 监控查询性能
4. 事件演化
- 规划事件模式演化
- 实现向上/向下兼容
- 考虑事件升级策略
- 维护事件文档
参考
本文为学习目的的个人翻译,译文仅供参考。
原文链接:Event Sourcing Explained: Benefits and Use Cases。
版权归原作者或原刊登方所有。本文为非官方译本;如有不妥,请联系删除。