本文源码:GitHub·点这里 || GitEE·点这里git
TCC分段提交适用分布式架构中对一致性、实时性要求较高的业务场景,在实际业务中也存在实时性比较低的业务,例如常见的短信通知,客户端消息,运营体系更新等业务,这时候为了减轻核心流程的复杂度和压力,能够采起最大努力通知方式实现柔性事务的管理。github
例如常见的第三方支付业务中,本地业务和支付端业务处理完成以后都会生成消息通知,基本流程以下:编程
上述流程的消息场景中有一些基础特色,在核心业务处理完成以后,发送消息通知,容许失败,在指定时间段内或者指定重试次数以后,容许消息丢失状况存在,即消息的不可靠性。缓存
在实际的支付系统中,启动每日对帐校验时会对当日的流水作校验,若是发现支付流水有未完成的流程,会有状态弥补,后续能够继续处理,这种手段在对帐中很经常使用。架构
分布式事务基于可靠消息最终一致性的实现方案,既然是可靠消息,则要求MQ必须支持事务管理,这样才能保证业务先后一致性。并发
RocketMQ在4.3版中开始支持分布式事务消息,采用2PC的思想来实现了提交事务消息,同时增长一个补偿逻辑来处理二阶段超时或者失败的消息,以下图所示:异步
上图说明了事务消息的大体方案,其中分为两个流程:正常事务消息的发送及提交、事务消息的补偿流程。分布式
1.1 发送及提交ide
(1)发送消息(half消息,即发送但不被消费);高并发
(2)服务端响应消息写入结果;
(3)根据发送结果执行本地事务,若是写入失败,此时half消息对业务不可见,本地逻辑不执行;
(4) 根据本地事务状态执行Commit或者Rollback(Commit操做生成消息索引,消息对消费者可见)
1.1 补偿流程
(1)对没有Commit/Rollback的事务消息(pending状态的消息),从服务端发起一次“回查”;
(2)Producer收到回查消息,检查回查消息对应的本地事务的状态;
(3)根据本地事务状态,从新Commit或者Rollback;
其中,补偿阶段用于解决消息Commit或者Rollback发生超时或者失败的状况。
1.3 设计原理
在RocketMQ事务消息的主要流程中,一阶段的消息如何对用户不可见。其中,事务消息相对普通消息最大的特色就是一阶段发送的消息对用户是不可见的。那么,如何作到写入消息可是对用户不可见呢?RocketMQ事务消息的作法是:若是消息是half消息,将备份原消息的主题与消息消费队列,而后改变主题为RMQ_SYS_TRANS_HALF_TOPIC。因为消费组未订阅该主题,故消费端没法消费half类型的消息,而后RocketMQ会开启一个定时任务,从Topic为RMQ_SYS_TRANS_HALF_TOPIC中拉取消息进行消费,根据生产者组获取一个服务提供者发送回查事务状态请求,根据事务状态来决定是提交或回滚消息。
基于上述RocketMQ事务消息可靠性的特色,便可以实现某类业务下事务的最终一致性。消息发送一致性是指产生消息的业务动做与消息发送一致,也就是说若是业务操做成功,那么由这个业务操做所产生的异步消息必定要发送出去,不然就业务失败回滚,消息也会丢弃。
流程基本以下:
该流程主要针对消息生产方,在实际开发中,消息的消费方也同样很难处理,要保证最终一致性,必然会面对一个问题,消费方异常,消息不断的重试,可能存在部分业务处理成功,部分业务处理失败的状况,这时候就要解决服务接口的幂等性问题。
编程中一个幂等操做的特色是其任意屡次执行所产生的影响均与一次执行的影响相同。就是说,一次和屡次请求某一个资源会产生一样的做用影响。
在复杂的异步流程中,尤为注意失败重试问题,一般支付流程中,每次接口被请求,对每一步数据更新的操做,都会前置一步状态查询的流程,用来判断下一步的数据更新是否该执行。
在系统服务接口请求中,任何明确的接口响应,例如失败或成功,这样业务流程都好处理,可是例如支付场景若是请求超时,如何判断服务的结果状态:客户端请求超时,本地服务超时,请求支付超时,支付回调超时,客户端响应超时等,或者基于MQ的不断重试机制,在部分业务异常状态下,始终没有返回成功,则消息会一直重试。
这就须要设计流程化的状态管理,尤为在消息重试机制下,不多会再次对重试的业务接口使用重度的事务控制,有些业务被执行完毕,只须要判断一个状态,下次消息重试跳过便可,只须要把未处理的业务补偿处理便可,在重试机制下,在部分业务没有所有执行成功以前,消息会一直重试,直到最终所有完成。
GitHub·地址 https://github.com/cicadasmile/data-manage-parent GitEE·地址 https://gitee.com/cicadasmile/data-manage-parent
推荐阅读:架构设计系列