许多开源的消息中间件都支持分布式事务,比如 RocketMQ消息队列、Pulsar 、QMQ。其思想几乎是和 本地消息表 是一样的,只不过是将可靠消息服务和 MQ 功能封装在一起,屏蔽了底层细节,从而更方便用户的使用。这种方案有时也叫做可靠消息最终一致性方案

以 RocketMQ 为例,消息的发送分成 2 个阶段:Prepare 阶段确认阶段

Prepare 阶段

  1. 生产者发送一个不完整的事务消息——HalfMsg 到消息中间件,消息中间件会为这个 HalfMsg 生成一个全局唯一标识,生产者可以持有标识,以便下一阶段找到这个 HalfMsg;
  2. 生产者执行本地事务。

注意:消费者无法立刻消费 HalfMsg,生产者可以对 HalfMsg 进行 Commit 或者 Rollback 来终结事务。只有当 Commit 了 HalfMsg 后,消费者才能消费到这条消息。

确认阶段

  1. 如果生产者执行本地事务成功,就向消息中间件发送一个 Commit 消息(包含之前 HalfMsg 的唯一标识),中间件修改 HalfMsg 的状态为【已提交】,然后通知消费者执行事务;

  2. 如果生产者执行本地事务失败,就向消息中间件发送一个 Rollback 消息(包含之前 HalfMsg 的唯一标识),中间件修改 HalfMsg 的状态为【已取消】。

消息中间件会定期去向生产者询问,是否可以 Commit 或者 Rollback 那些由于错误没有被终结的 HalfMsg,以此来结束它们的生命周期,以达成事务最终的一致。

之所以需要这个询问机制,是因为生产者可能提交完本地事务,还没来得及对 HalfMsg 进行 Commit 或者 Rollback,就挂掉了,这样就会处于一种不一致状态。

ACK 机制

消费者消费完消息后,可能因为自身异常,导致业务执行失败,此时就必须要能够重复消费消息。RocketMQ 提供了 ACK 机制,即 RocketMQ 只有收到服务消费者的 ack message 后才认为消费成功。

所以,服务消费者可以在自身业务逻辑执行成功后,向 RocketMQ 发送 ack message,保证消费逻辑执行成功。