事件溯源

事件溯源是构建业务逻辑和长久化聚合的另一种抉择。
通过聚合一系列事件的形式长久化保留。每个事件代表聚合的一次状态变动。应用程序通过重放来从新创立聚合的以后状态。

模式:事件溯源应用一系列示意状态更改的畛域事件来长久化聚合。

1. 传统长久化技术的问题

  • 对象和关系的“阻抗失调”
    关系型数据的表格构造模式,与畛域模型及其简单关系的图状构造之间,存在基本概念不匹配的问题。

  • 不足聚合的历史
    传统长久化的另一个限度是,它只存储聚合的以后状态。聚合更新后,其先前的状态将会失落。
    如果应用程序必须保留聚合的历史,那么必须实现相应的业务逻辑。实现这个逻辑是十分耗时的一项工作,因为其中还有波及到复制必须与业务逻辑保持一致的代码。

  • 实现审计性能十分繁琐且容易出错
    为了满足安全性或监管的要求,要实现审计性能以反对。
    挑战在于,除了这个是一个耗时的工作之外,负责审计日志的业务代码,可能与业务逻辑产生偏离,导致各种谬误。

  • 事件公布凌驾于业务逻辑之上
    传统长久化的另一个限度是,它通常不反对公布畛域事件。

2. 什么是事件溯源

事件溯源是一种以事件为核心的技术,用于实现业务逻辑和聚合的长久化。
事件溯源通过事件来长久化聚合
通过设置事件存储库(event表),构造如下:

evenv_idevent_typeentity_typeentity_idevent_data
101OrderCreatedOrder101{...}
102OrderApprovedOrder101{...}
103OrderShippedOrder101{...}
104OrderDeliveredOrder101{...}
...............

记录了Order变动的事件及所需的数据,通过加载事件存储库,可重放事件加载聚合。

  • 一般来说,依照以下步骤:
  1. 加载聚合事件列表
  2. 应用默认构造方法创立聚合实例
  3. 调用聚合事件绝对应的apply办法,重放事件
  • 事件溯源罕用实现如下:
  1. 应用process办法接受命令,返回事件列表
  2. 应用apply办法,承受事件,更新聚合

2.1 通过事件来长久化聚合

2.2 事件代表状态的扭转

2.3 聚合办法都与事件相干

2.3.1 创立聚合的步骤如下:

  1. 应用聚合默认的构造函数实例化聚合根
  2. 调用process办法,生成事件列表1
  3. 遍历事件列表1,并调用apply办法更新聚合的状态
  4. 将事件列表保留至事件存储库

2.3.2 更新聚合的步骤如下:

  1. 从事件存储库加载事件列表1
  2. 应用其默认构造函数实例化聚合根
  3. 遍历加载的事件列表1,并在聚合根上调用apply办法
  4. 调用process办法以生成事件列表2
  5. 遍历事件列表2,并调用apply办法更新来聚合的状态
  6. 将新事件存储至事件存储库

2.4 并发更新

两个或多个申请同时更新同一聚合。
对于并发,防止问题呈现的形式是,进行串行化的解决。

  • 对事件存储库新增一列,is_publish

    event_idis_publish
    1010
  • 将事件存储至事件存储库(即时),is_publish为0
  • 投递事件至音讯代理
  • 将事件标记为已公布,is_publish=1
    事件执行反馈记录,这里不聊

2.5 畛域事件的演变

事件溯源的构造分为三个档次:

  1. 由一个或多个聚合组成
  2. 定义每个聚合收回的事件
  3. 定义事件的构造

2.6 事件溯源的优劣

2.6.1 事件溯源的益处

牢靠的公布畛域事件
保留聚合的历史
最大水平的防止对象和关系的“阻抗失调”
为开发者提供一个时光机

2.6.2 事件溯源的弊病

编程模式有肯定的学习曲线
基于消息传递的应用程序的复杂性
处理事件的演变有肯定的难度
随着工夫的推移,畛域模型及构造都可能会有调整。

  1. 迁徙旧构造,以反对以后最新的畛域模型
  2. 代码中减少适配器,以兼容旧构造
    删除数据有肯定的难度
  3. 事件溯源自身是要保留聚合的历史,永恒的保留数据,所以传统的做法是进行软删除
  4. 应用软删除应用多种数据,然而依据欧洲的数据保护和隐衷法规(GDPR),应用程序必须彻底删除用户的个人信息。
    做法是,通过用户设置UUID,依据UUID关联敏感数据。删除数据时,删除关联即可。
  5. 查问事件存储库十分有挑战性
    须要在事件存储库,找到没有间接搜寻条件的数据。
    通过CQRS可实现该查问

2.7 通过快照来进步溯源的性能