事件溯源
- 使用一系列表示状态变更的领域事件来持久化聚合
- 好处
- 保留聚合的历史记录,方便审计、监管
- 弊端
- 有学习曲线
- 查询通常困难,需要使用CQRS
- 事件演化时,代码的处理变得困难
- 比如说一次升级之后,处理事件的信息变多了,而之前的事件还没有消费完
- 解决方法,加载事件时,补充事件信息到最新版本
- 比如说一次升级之后,处理事件的信息变多了,而之前的事件还没有消费完
传统持久化的问题
- 只保留当前状态
- 聚合更新后,先前的状态丢失
- 如果业务需求记录历史,这又是一个耗时的工具,开发人员自己实现
- 审计繁琐
- 耗时
- 容易和业务逻辑偏差
- 比如新增一个逻辑,但是忘了记录到历史中
- 无法把自动发送消息作为更新数据库的一部分
- 就是更新业务数据和发送事件消息同时成功,同时失败
- 对象和关系“阻抗失调”
- 面向对象和关系数据库不是相辅相成的
- 越是复杂的面向对象系统设计,越是难以用关系数据库来表示
事件溯源
- 以事件为中心,用于实现业务逻辑和聚合的持久化
- 就是把事件存放在数据库中,并把相关的业务数据存下来
- 存储信息
- 唯一事件ID
- 事件类型
- 聚合标识
- 实体类型
- 聚合根的类型
- 比如这条记录是以订单为主线
- 实体ID
- 聚合根
- 实体类型
- 序列化的事件
- 通常是大json
- event_data
- 事件表示状态的改变
- 每一个聚合的状态发生变化时,它必须发出一个事件
- 事件必须包含聚合执行状态变化所需的数据
如何处理并发更新聚合
- 乐观锁
- 使用版本列来判断是否已更改
- 版本可以使用事件ID,也可在事件存储表中
- 使用版本列来判断是否已更改
如何使用事件存储表发送事件
- 轮询
- 在事件表中加一列,表示事件是否以及发送
- 事务日志拖尾
- 从事件表中读取事件,发送到消息代理
- 由消息代理来保证消息可靠发布
如何回滚事件
- 使用快照
- 就是记录一个事件发生前快照
事件消费时,注意幂等
- 实际上,我觉得这个应该由消费方来保证,因为无法百分百保证不充分发送消息。
- 一种重复是事件ID重复,一种是业务数据重复(就是两个事件实际上是同一个)