1.领域事件的实质
主要是领域中的实体因为某种动作产生了属性变化,属性的变化对其他调用方有时需要感知到,以便完成业务处理逻辑,比如订单状态的变化。
领域事件没有必要使用事件溯源方式来实现(把每次的状态变化都记录下来),现实场景很多也仅仅是有变化的时候发送一个消息。
事件发送后是异步处理的,异步处理就需要考虑事务的一致性,当一个消息处理失败的时候另一个要能够支持回滚。比如一个订单利用多种支付方式同时支付不同部分的金额,比如个人余额、第三方账号,个人余额是同步调用扣款,第三方都是异步消息,当异步消息告诉扣款失败的话,个人余额扣的钱要支持回滚。
image.png内部事件:系统自己发送自己消费,可以保存稍微复杂的结构,自己能识别就行。
外部事件:跨服务调用的,一般只保存扁平的结构,一般是相关的id。
2. 领域事件的实现方式
现在已经有很多消息队列了,有几种模式
- 发布订阅模型:多对多、支持广泛,一个topic可以被多个订阅者消费,新增订阅者发送方无影响。
- 消息队列
- 一对一的:亚马逊的SQS,很不好,只能一个发送方一个接收方,继续增加需要新申请另一个SQS队列,也不支持NACK。
- 多对一的:多个业务方都把数据往一个队列写入,一个消费方读取,比如消费方用这些数据做流式计算。
3. 事件溯源
如果系统总是只存储领域模型当前的状态,则无法理解系统是如何变成该状态的,不能分析过去的行为以揭示新的见解或者找出出错的地方。比如订单系统,如果存储了订单各个状态的变化,并按照时间顺序存储,就可以分析订单增加或者减少的原因,比如配送时间是否过长了、商家接单是否慢了,并找出新的增长点。
3.1 事件溯源的设计
- 通过记录事件,以便推导系统的任意状态
- 利用投影函数,不同维度分析
- 直接存储每次的快照,会导致占空间比较多。
3.2事件溯源在聚合的实现
定义一个基类,让聚合拥有保存事件流和根据事件流更新属性的能力
image.png image.png image.png重载了许多When方法,处理在收到领域事件后对聚合属性的更新
image.png为了支持持久化,增加快照相关的获取和初始化方法
image.png image.png image.png存储事件溯源的数据库必须支持创建、追加、搜索,处理并发。
3.3 事件溯源在价值
- 可以更好的进行商业分析。
- 专注表述性行为的聚合
可以更清楚的表述领域的概念,因为用的是下面的模式
when {domain event} {apply business rules}
3.方便调试
遇到问题可以很容易恢复到聚合的特定状态去定位问题。
4.简化持久化机制
ORM持久化聚合存在阻抗不匹配,使用事件溯源可以方便自己在业务里面根据事件自定义实现聚合属性的更新,比ORM灵活。
3.4 事件溯源的代价
1、 随着领域了解,领域模型会持续演化,会需要修改旧的事件格式,需要增加版本号控制兼容性问题。
2、需要学习新的事物,快照、投影、时态查询可能是新的事务,需要额外成本。
3、需要大量的存储,因为事件有时是非常多的,存储这些一定会占用极大的空间,有时甚至不能使用mysql存储。
网友评论