发件箱
发件箱模式,是分布式系统中常用的一种模式。当一个系统要给另外一个系统发送消息,为了避免消息丢失,消息和业务数据不一致,我们可以在业务处理的事务中,把要发送的消息写入到本地数据库的一个发件箱里,然后再事务外去扫描这个发件箱,把消息发送出去。 这里有两个要点
- 在业务处理的数据库事务中把要发送的消息记录到发件箱
- 在事务之外,发送消息,标记消息发送成功,发送失败的重试直到成功
这个发件箱,可以用数据库的一个或多个数据表实现。
在DDD中什么场景下要使用发件箱模式?
只要不能利用数据库事务完成强一致性,要最终一致性,都可以使用这个模式,不仅是DDD,所有的分布式系统都如此。在DDD中,最常见的就是利用发件箱模式确保监听领域事件的对象一定能收到领域事件。
采用发件箱模式发送领域事件,如何保证顺序?
一般情况下,我们不需要所有的领域事件之间都严格的保证顺序,一般只要一个聚合或一些聚合的消息保证有序即可。要设计一种技术实现方式,在领域事件生成的时候,给它生成一个排序标志,这样后续发送的时候可以按照这个排序值决定发送顺序。比如:
- 以数据库自增序列为排序值
- 以时间戳为自增序列(注意时间精度)
- redis自增计数器
如果是分布式消费,使用MQ中间件,那么要在把领域事件发送到MQ的时候,根据MQ设计消息排序。不同的MQ的消息顺序机制不同,要具体问题具体分析。
万一消费失败怎么办?
重新发送,重新消费。
如何避免重复消费?
如果重复消费不会影响业务逻辑的,就兼容重复消费。否则,要在消费端做幂等。为了支持消费端做幂等,生成领域事件的时候,要给领域事件生成id,用来作为幂等消费的唯一标识。