什么是可靠消息最终一致性方案

我们将要介绍一种生产上最常用的分布式事务解决方案——可靠消息最终一致性方案。所谓可靠消息最终一致性方案,其实就是在分布式系统当中,把一个业务操作转换成一个消息,然后利用消息来实现事务的最终一致性

比如从 A 账户向 B 账户转账的操作,当服务 A 从 A 账户扣除完金额后,通过消息中间件向服务 B 发一个消息,服务 B 收到这条消息后,进行 B 账户的金额增加操作。

可靠消息最终一致性方案一般有两种实现方式,原理其实是一样的:

  1. 基于 本地消息表
  2. 基于 支持分布式事务的消息中间件,如 RocketMQ 等

示例

我们以一个电子商务支付系统的核心交易链路为示例,来更好的理解下可靠消息最终一致性方案。

交易链路

假设我们的系统的核心交易链路如下图。用户支付订单时,首先调用订单服务的对外接口服务,然后开始核心交易链路的调用,依次经过订单业务服务、库存服务、积分服务,全部成功后再通过 MQ 异步调用仓储服务:

上图中,订单业务服务、库存服务、积分服务都是同步调用的,由于是核心链路,我们可以通过 TCC 事务 来保证分布式事务的一致性。而调用仓储服务可以异步执行,所以我们依赖 RocketMQ 来实现分布式事务。

事务执行

接着,我们来看下引入 RocketMQ 来实现分布式事务后,整个系统的业务执行流程发生了哪些变化,整个流程如下图:

  1. 当用户针对订单发起支付时,首先订单接口服务先发送一个 half-msg 消息给 RocketMQ,收到 RocketMQ 的成功响应(注意,此时仓储服务还不能消费消息,因为 half-msg 还没有确认)。

  2. 然后,订单接口服务调用核心交易链路,如果其中任一服务执行失败,则先执行内部的 TCC 事务回滚;

  3. 如果订单接口服务收到链路失败的响应,则向 MQ 投递一个 rollback 消息,取消之前的 half-msg;

  4. 如果订单接口服务收到链路成功的响应,则向 MQ 投递一个 commit 消息,确认之前的 half-msg,那仓库服务就可以消费消息;

  5. 仓储服务消费消息成功并执行完自身的逻辑后,会向 RocketMQ 投递一个 ack message,以确保消费成功。

注意,如果因为网络原因,导致 RocketMQ 始终没有收到订单接口服务对 half-msg 的 commit 或 rollback 消息,RocketMQ 就会回调订单接口服务的某个接口,以查询该 half-msg 究竟是进行 commit 还是 rollback。

总结

可靠消息最终一致性方案,一般适用于异步的服务调用,比如支付成功后,调用积分服务进行积分累加、调用库存服务进行发货;在银行交易系统中,使用可靠消息最终一致性确保跨银行转账等操作的一致性,提高系统的可用性。

最基本的思想就两点:

  1. 通过引入消息中间件,保证生产者对消息的 100% 可靠投递;
  2. 通过引入 Zookeeper,保证消费者能够对未成功消费的消息进行重新消费(消费者要保证自身接口的幂等性)。

优缺点

可靠消息最终一致性方案是目前业务主流的分布式事务落地方案,其优缺点主要如下:

优点:
消息数据独立存储,降低业务系统与消息系统间的耦合。

缺点:
一次消息发送需要两次请求,业务服务需要提供消息状态查询的回调接口。