触发领域事件
领域事件由外部命令触发。触发命令可以是领域服务,也可以是实体的某一个方法或者行为。
触发事件的用法
走canal增量同步数据库数据,通过监听特定表的数据变更来触发生成事件的调用。如此有利于主流业务的解耦,提高维护和可读性。(具体生成事件的操作当然还是放在对应领域的微服务中,canal监听消费端可以理解为一个任务调度平台)。这样的实现逻辑相对简单。
那不同领域事件,如何处理呢?
3 处理领域事件
3.1 微服务内
领域事件发生在微服务内的聚合间,领域事件发生后完成事件实体的构建和事件数据持久化,发布方聚合将事件发布到事件总线,订阅方接收事件数据完成后续业务操作。
微服务内大部分事件的集成,都发生在同一进程,进程自身即可控制事务。但一个事件若同时更新多个聚合,按一次事务只更新一个聚合原则,可考虑引入事件总线。
微服务内应用服务,可通过跨聚合的服务编排和组合,以服务调用方式完成跨聚合访问,这种方式通常应用于实时性和数据一致性要求高的场景。这个过程会用到分布式事务,以保证发布方和订阅方的数据同时更新成功。
在微服务内,不是说少用领域事件,而是推荐少用事件总线。DDD是以聚合为单位进行数据管理,若一次操作会修改同一微服务内的多个聚合的数据,就需保证多个聚合的数据一致性。
为了解耦不同聚合,需采用分布式事务或事件总线,而事件总线不太方便管理服务和数据的关系,可用类似saga之类的分布式事务技术。总之需确保不同聚合的业务规则和数据一致性。
3.2 微服务间
跨微服务的领域事件会在不同限界上下文或领域模型间实现业务协作,主要为解耦,减轻微服务间实时服务访问压力。
领域事件发生在微服务间较多,事件处理机制也更复杂。跨微服务事件可推动业务流程或数据在不同子域或微服务间直接流转。
跨微服务的事件机制要总体考虑事件构建、发布和订阅、事件数据持久化、MQ,甚至事件数据持久化时还可能需考虑引入分布式事务。
微服务间访问也可采用应用服务直接调用,实现数据和服务的实时访问,弊端就是跨微服务的数据同时变更需要引入分布式事务。分布式事务会影响系统性能,增加微服务间耦合,尽量避免使用。
5 领域事件设计
5.1 构建和发布
基本属性
至少包括如下:
- 事件唯一标识(全局唯一,事件能够无歧义在多个限界上下文中传递)
- 发生时间
- 事件类型
- 事件源
即主要记录事件本身以及事件发生背景的数据。
业务属性
记录事件发生那刻的业务数据,这些数据会随事件传输到订阅方,以开展后续业务操作。
事件基本属性和业务属性一起构成事件实体,事件实体依赖聚合根。领域事件发生后,事件中的业务数据不再修改,因此业务数据可以以序列化值对象的形式保存,这种存储格式在消息中间件中也比较容易解析和获取。
为保证事件结构的统一,通常创建事件的基类,子类可自行继承扩展。由于事件没有太多业务行为,实现一般比较简单。
事件发布前需先构建事件实体并持久化。
事件实体的业务数据推荐按需发布,避免泄露不必要业务信息。
事件发布方式
- 可通过应用服务或者领域服务发布到事件总线或MQ
- 也可从事件表中利用定时程序或数据库日志捕获技术获取增量事件数据,发布到MQ