每次我们在数据库中运行 UPDATE 语句,某些东西就消失了。旧值,无论刚才在那里的是什么,都消失了。

事实上,大多数数据库设计为忘记。每个 UPDATE 覆盖之前的内容,每个 DELETE 完全移除它,应用只剩下当前状态的快照。我们接受这是正常的,因为这是最自然的思考方式。

但如果你的系统需要回答不同类型的问题:不仅是”当前状态是什么?“而是”我们如何到达这里?”

这就是事件溯源构建来回答的问题。解决方案既比它首先出现的更有回报也更有要求。在本文中,我们将看看事件溯源以及它的好处和权衡。

问题

传统数据库方法有根本限制。当你运行 UPDATE 时,旧值消失。当你运行 DELETE 时,它完全移除。你只剩下当前状态的快照。

这对许多应用工作良好。但有些场景需要知道历史:

  • 审计要求:谁在什么时候改变了什么?
  • 调试:系统如何到达这个状态?
  • 合规性:需要完整的历史记录
  • 业务分析:理解模式和趋势

事件溯源解决方案

事件溯源通过存储事件序列而不是当前状态来解决这个问题。

核心概念

不是更新当前状态,每个变化作为事件存储:

初始状态:账户余额 = $100
事件 1:存款 $50
事件 2:取款 $30
事件 3:存款 $20
当前状态:$140(通过重放事件计算)

工作原理

  1. 事件捕获:每个状态变化作为不可变事件存储
  2. 事件存储:事件按时间顺序存储在事件存储中
  3. 状态重建:当前状态通过重放所有事件计算
  4. 快照:定期创建快照以优化重建性能

好处

1. 完整审计跟踪

  • 每个变化都记录
  • 知道谁在什么时候做了什么
  • 满足合规要求

2. 时间旅行

  • 可以重建任何时间点的状态
  • 调试历史问题
  • 分析历史趋势

3. 灵活性

  • 可以添加新的读取模型
  • 可以从相同事件派生不同视图
  • 容易适应新需求

4. 可追溯性

  • 理解系统如何到达当前状态
  • 调试更容易
  • 业务洞察更丰富

权衡

1. 复杂性

  • 更复杂的架构
  • 需要事件版本控制
  • 查询更复杂

2. 性能

  • 状态重建可能慢
  • 需要快照优化
  • 存储更多数据

3. 学习曲线

  • 团队需要学习新模式
  • 思维模式转变
  • 工具链不同

4. 事件模式演化

  • 事件模式变化困难
  • 需要向后兼容
  • 可能需要事件升级

用例

适合事件溯源的场景

  1. 金融系统

    • 需要完整审计跟踪
    • 合规要求严格
    • 需要时间旅行
  2. 电商订单系统

    • 订单状态变化复杂
    • 需要追溯订单历史
    • 需要分析购买模式
  3. 库存管理

    • 需要跟踪库存变化
    • 需要审计库存调整
    • 需要预测趋势
  4. 工作流系统

    • 复杂的状态机
    • 需要审计工作流
    • 需要重放事件

不适合事件溯源的场景

  1. 简单 CRUD 应用

    • 不需要历史
    • 简单读写模式
    • 性能要求高
  2. 实时性要求极高

    • 状态重建太慢
    • 需要即时响应
    • 缓存更有效
  3. 数据量巨大

    • 事件存储过大
    • 重建成本太高
    • 快照管理复杂

实施考虑

1. 事件设计

  • 使用过去时态命名(OrderCreated、PaymentProcessed)
  • 包含所有相关信息
  • 保持事件不可变
  • 考虑事件版本控制

2. 事件存储

  • 选择合适的事件存储
  • 考虑事件追加性能
  • 实现快照策略
  • 规划事件归档

3. 查询优化

  • 构建读取模型(CQRS)
  • 使用投影优化查询
  • 实现缓存策略
  • 监控查询性能

4. 事件演化

  • 规划事件模式演化
  • 实现向上/向下兼容
  • 考虑事件升级策略
  • 维护事件文档

参考

本文为学习目的的个人翻译,译文仅供参考。

原文链接:Event Sourcing Explained: Benefits and Use Cases

版权归原作者或原刊登方所有。本文为非官方译本;如有不妥,请联系删除。