消息队列与领域事件

消息队列

两种模式

  1. Point-ti-Point: Queue (点对点: 队列)
  2. Pub/Sub: Topic (发布/订阅: 主题)

(非)持久订阅

发布/订阅分为非持久订阅(Redis pub/sub)和持久订阅(ActiveMQ). 持久订阅: 发布者在订阅者处于非活动状态时发布的消息,将在订阅者再次处于活跃状态时重新发布。

Point-to-Point Pub/Sub
一个消费者(不可重复消费) 多个订阅者(可重复消费)
模式(懒/轮询) 模型
异步 “同步”
生成-消费队列 观察者

领域事件

消息队列和事件驱动有密不可分的关系。

领域事件(Domain Events)是领域驱动设计(Domain Driven Design,DDD)中的一个概念。

在DDD中有一条原则:一个业务用例对应一个事务,一个事务对应一个聚合根,也即在一次事务中,只能对一个聚合根进行操作。

在DDD中有一条原则:一个业务用例对应一个事务,一个事务对应一个聚合根,也即在一次事务中,只能对一个聚合根进行操作。但是在实际应用中,我们经常发现一个用例需要修改多个聚合根的情况,并且不同的聚合根还处于不同的限界上下文中。比如,当你在电商网站上买了东西之后,你的积分会相应增加。这里的购买行为可能被建模为一个订单(Order)对象,而积分可以建模成账户(Account)对象的某个属性,订单和账户均为聚合根,并且分别属于订单系统和账户系统。显然,我们需要在订单和积分之间维护数据一致性,通常的做法是在同一个事务中同时更新两者,但是这会存在以下问题:

  • 违背DDD中”单个事务修改单个聚合根”的设计原则;
  • 需要在不同的系统之间采用重量级的分布式事务(Distributed Transactioin,也叫XA事务或者全局事务);
  • 在不同系统之间产生强耦合。
通过引入领域事件,我们可以很好地解决上述问题。 总的来说,领域事件给我们带来以下好处:
  • 解耦微服务(限界上下文);
  • 帮助我们深入理解领域模型;
  • 提供审计和报告的数据来源;
  • 迈向事件溯源(Event Sourcing)和CQRS等。

“电商订单”例子

领域事件