《微服务架构设计模式》-学习总结06

本篇主要总结第六章:使用事件溯源开发业务逻辑

传统的持久化技术

将类映射到数据库表,将类的字段映射到数据表中的列,类的实例映射到数据表中的行。比较成熟的ORM,像Mybatis、JPA等。

作者上来就指出传统持久化技术的弊端,但是看完本章后个人感觉,在更多的项目实践中,还是传统的持久化技术更香,原因就一个——技术成熟。来看看作者说的弊端:

  • 对象与关系的“阻抗失调”(impedance mismatch)
    • 这个缺点在字面上有点费解,其实就是说类和对象是面向对象的产物,面向对象的思想与关系型数据的准则之间本身不是相辅相承的关系。越是复杂的面向对象系统设计,越是难以用关系型数据库来表达。
  • 缺乏聚合历史
    • 就是只有记了最终状态没记录对象的历史变化(但是大多数的传张后台系统都会有审计日志的需求,其实还是变相记录了部分对象历史的)
  • 实施审计功能将非常烦琐且容易出错
  • 事件发布凌驾于业务逻辑之上
    • 事件发布与业务逻辑代码不能完全同步

事件溯源

事件溯源将每个聚合作为一系列事件来持久化保存,每个事件代表聚合状态的一次改变。

采用事件溯源后,聚合中具体业务逻辑的方法,都要改造成process+apply的方式实现:

  • process:接受外部调用并生成事件,但不更改聚合的状态
  • apply:接受事件并修改聚合状态

这是一个侵入性较强的操作,如果之前不熟悉事件溯源开发,可能会在这实施项目时遇到问题。而且创建和更新聚合都需要遵守先加载重放,再生成事件,然后再apply事件的模式。

创建聚合的步骤:

  1. 使用聚合的默认构造函数实例化聚合根
  2. 调用process()以生成新事件
  3. 遍历新生成的事件并调用apply()来更新聚合的状态。
  4. 将新事件保存在事件存储库中。

更新聚合的步骤:

  1. 从事件存储库中加载聚合事件
  2. 使用基默认构造函数实例化聚合根
  3. 遍历加载的事件,并在聚合根上调用apply()方法进行事件重放
  4. 调用其process()方法以生成新事件
  5. 遍历新生成的事件并调用apply()来更新聚合的状态。
  6. 将新事件保存在事件存储库中。

实施事件溯源还需要注意:

  • 如果聚合的事件非常多,导致重放效率越来越低,则需要考虑引入聚合的快照(Snapshot),首先选择合理的快照,再重放快照之后的事件得到最新的聚合。
  • 使用乐观锁解决同时更新同一聚合的情况。
  • 事务溯源还必须实现消息处理的幂等。
  • 需要解决事件演化更新的问题,确保不同历史版本的事件可以兼容最新的聚合重放。

事件溯源的好处

  • 可靠地发布领域事件
  • 保留聚合的历史
  • 最大限度地避免对象与关系的“阻抗失调”问题
  • 为开发者提供一个“时光机”

事件溯源的弊端

  • 有一定的学习曲线
  • 基于消息传递的应用程序的复杂性
  • 处理事件的演化更新有一定难度
  • 删除数据存在一定难度
  • 查询事件存储库非常有挑战性

学习总结

事件溯源是一个业务逻辑设计的新颖模式。区别于传统的业务逻辑存储”结果“,把对象的最新状态通过ORM或者直接数据库操作存储在数据库中。事件溯源的理念是存储”过程“,把对象每次状态变化都以事件记录的形式存放在数据库中。

我理解事件溯源最直接的两个好处:

  • 第一,不再需要复杂的数据库表设计,理论上一个事件储存表就可以应用到所有对象上。
  • 第二,做审计功能的时候,后端几乎没有额外的工作量,天然就支持。

而要真正实现事件溯源要做的准备不少:

  • 首先,要学会使用事件溯源;
  • 其次,如何定义较好抽象的事件也是一个让开发人员头痛的事情,开发人员之间必须明确理解每个事件的意义,防止出现重复冗余的事件。
  • 第三,每个事件可能包含的数据不同,如果要统一格式存储,必然要用到序列化为文本或二进制的通用字段。这对于查询的业务逻辑来说,编码将非常麻烦。比如,要找出某个属性值为5的所有聚合的实例,需要加载并重放所有聚合,然后再查询属性为5的聚合实现。

因此,我觉得事件溯源更适合于对历史事件要求非常苛刻的项目,一般的业务需求中,只需要在对象的几个关键节点上记录事件即可。微

参考文献:

Event Stream Processing, Streaming Data, and CEP Explained

你可能感兴趣的:(java,数据库,大数据,python,设计模式)