领域事件

领域事件和事件总线

An event is something that has happened in the past. A domain event is, logically, something that happened in a particular domain, and something you want other parts of the same domain (in-process) or domain in aonther bounded context to be aware of and potentially react to.

领域事件是领域模型中非常重要的部分,用来表示领域中发生的事件。一个领域事件将导致进一步的业务操作,有助于形成完整的业务闭环。领域事件主要用于解耦微服务,各个微服务之间不再是强一致性,而是基于事件的最终一致性。

微服务内通过事件沟通

Domain Event 是由一个特定领域触因为一个用户 Command 触发的发生在过去的行为产生的事件,而这个事件是系统中其它部分感兴趣的。Domain Event 如此重要是因为在现在的分布式环境下,没有一个业务系统是割裂的,而 Messaging 绝对是系统之间耦合度最低,最健壮,最容易扩展的一种通信机制。因此理论上它是分布式系统的必选项。但是目前大部分系统的 Event 都设计的很随性,没有统一的指导和规范,导致 Event 滥用和无用的情况时有发生,而 Domain Event 给我们一个很好的方向,指引我们该如何设计我们系统的 Event。

微服务内的领域事件可以通过事件总线或利用应用服务实现不同聚合之间的业务协同。当微服务内发生领域事件时,由于大部分事件的集成发生在同一个线程内,不一定需要引入消息中间件。但一个事件如果同时更新多个聚合数据,按照 DDD“一个事务只更新一个聚合根”的原则,可以考虑引入消息中间件,通过异步化的方式,对微服务内不同的聚合根采用不同的事务。

事件构建

Your Domain Event type names should be a statement of a past occurrence, that is, a verb in the past tense.

因为表示的是过去事件,所以推荐命名为 Domain Name + 动词的过去式 + Event。这样比较可以确切的表达业务语义。下面是几个举例:

  • CustomerCreatedEvent,表示客户创建后发出的领域事件。
  • OpportunityTransferedEvent,表示机会转移后发出的领域事件。
  • LeadsCreatedEvent,表示线索创建后发出的领域事件。

Event 的内容有两种形式:

  • Enrichment:也就是在 Event 的 payload 中尽量多多放 data,这样 consumer 就可以自恰(Autonomy)的处理消息了。
  • Query-Back:这种是在 Event 中通过回调拿到更多的 data,这种形式会加重系统的负载,performance 也会差一些。

所以如果要在 Enrichment 和 Query-Back 之间做选择的话,首先推荐使用 Enrichment。

事件总线

事件总线位于基础层,为应用层和领域层服务提供事件消息接收和分发等服务。其大致流程如下:服务触发并发布事件、事件总线事件分发。

  • 如果是微服务内的订阅者(微服务内的其它聚合),则直接分发到指定订阅者。

  • 如果是微服务外的订阅者,则事件消息先保存到事件库(表)并异步发送到消息中间件。

  • 如果同时存在微服务内和外订阅者,则分发到内部订阅者,并将事件消息保存到事件库(表)并异步发送到消息中间件。为了保证事务的一致性,事件表可以共享业务数据库。也可以采用多个微服务共享事件库的方式。当业务操作和事件发布操作跨数据库时,须保证业务操作和事件发布操作数据的强一致性。

事件数据持久化与溯源

事件数据的持久化存储可以有两种方案,在项目实施过程中根据具体场景选择最佳方案。

  • 事件数据保存到微服务所在业务数据库的事件表中,利用本地事务保证业务操作和事件发布操作的强一致性。
  • 事件数据保存到多个微服务共享的事件库中。需要注意的一点是:这时业务操作和事件发布操作会跨数据库操作,须保证事务的强一致性(如分布式事务机制)。

事件数据的持久化可以保证数据的完整性,基于这些数据可以完成跨微服务数据的一致性比对。Event Sourcing 是在 Domain Event 上面的一个扩展,是一个可选项。也就是要有一个 Event Store 保存所有的 Events,其实如果你是用 MetaQ 作为 Event 机制的话,这些 Events 都是存储在 MetaQ 当中的,只是 MetaQ 并没有提供很好的 Event 查询和回溯,所以如果决定使用 Event Sourcing 的话,最好还是自己单独建立一个 Event Store。

使用 Event Sourcing 主要有以下好处,如果用不到的话,完全可以不用,但是 Domain Event 还是强烈建议要使用。

  • Event Sourcing 存储了所有发生在 Core Domain 上面的事件。
  • 基于这些事件,我们可以做系统回放,系统 Debug,以及做用户行为的分析(类似于打点)
上一页