- 一、总览
- 二、立即回滚
- 1.2PC(XA)
- 三、最终一致性
- 1.TCC补偿式事务
- 2.可靠消息+最大努力通知
- 四、总结
前面我们提到分布式的基本理论及根据理论解决分布式事务的问题。
public void bussiness(){
//扣减库存
httpclient.storage();
//生成订单
httpclient.order();
//减去金额
httpclient.account();
}
在减去用户金额时失败,那么如何库存和订单数据立即回滚则满足CAP(或者ACID),如果是在一段时间内回滚,达到数据最终一致性则满足base。
根据是否立即回滚或者一段时间内回滚衍生出几种解决方案
立即回滚:两阶段(三阶段)提交(2PC、3PC)
最终一致性:TCC补偿式事务、消息事务保证、最大努力通知
2PC即两阶段提交协议,也叫XA协议,是将整个事务流程分为两个阶段,准备(prepare phase)阶段和提交阶段(commit phase)。
- 第一阶段:事务协调器要求每个涉及到事务的数据库预提交(precommit)操作,并反映是否可以提交
- 第二阶段:事务协调器要求每个数据库提交数据。
其中,如果有任何一个数据库否决这次提交,那么所有数据库都会被要求回滚他们在此事务中的那部分消息
目前大多数据库都支持2PC,MySQL5.5、SQL Server2005、Oracle7开始支持
优缺点
总的来说XA比较简单,而且一旦商业数据库实现了XA协议,使用分布式事务的成本非常低。但是,XA有致命的缺点,性能太不理想,特别是并发量高的场景,如电商秒杀。
为什么呢?
- 1.两阶段提交涉及多次节点间的网络通信,通信时间太长。
- 2.事务时间变长,那么锁定资源的时间变长,各种事务等待现象
- 3.mysql的XA没有记录prepare阶段日志,准备切换会导致主库和备库数据不一致
TCC采用的补偿机制,核心思想是:针对一个大事务和大事务中的小事务操作,都要注册一个与其对应的确认和补偿(撤销)操作。TCC模式要求服务提供三个接口:Try、/confirm/i、Cancel。
- Try:主要是对业务系统做检测及资源预留
- /confirm/i:真正执行业务,不作任何业务检查;只使用Try阶段预留的业务资源;/confirm/i操作需满足幂等性
- Cancel:释放Try阶段预留的业务资源;Cancel操作需满足幂等性
整个TCC业务分为两个阶段
- 第一阶段:大事务业务分别调用小事务的try操作,并在活动管理器中登记所有的小事务。当所有小事务调用成功或者某个小事务调用失败,则进入第二阶段
- 第二阶段:活动管理器根据第一阶段的执行结果来执行/confirm/i或cancel操作。如果第一阶段所有try操作都成功,则活动管理器调用所有小事务的/confirm/i操作。否则调用所有小事务的cancel操作
优缺点
- 1./confirm/i和Cancel的幂等性很难保证
- 2.复杂场景下不推荐使用
- 3.代码量庞大、耦合度高。而且非常有局限性,因为很多业务是无法简单实现回滚的
- 4.全局串行,不适合并发量高的场景
不保证数据一定能通知成功,但会提供可查询操作接口进行核对。一般用于调第三方服务时,如调用微信或支付宝后的支付结果通知。也是结合MQ进行实现,通过MQ发送http请求,设置最大通知次数。达到通知次数后不再通知
结合上面案例说明
public void bussiness(){
//扣减库存
httpclient.storage();
//生成订单
httpclient.order();
//减去金额
httpclient.account();
}
在减去用户金额失败时,将失败消息发送到MQ中,库存和订单服务订阅MQ失败消息执行回滚逻辑。当然也需要考虑消息可靠性、幂等性等问题。
优缺点
适用于并发量高的场景,但是牺牲了部分一致性,采用了最终一致性。如果最后事务死活回滚不了就要考虑人工介入了。
并发量小情况:使用2PC、3PC、TCC模式,如现在阿里提供的seata组件
并发量大情况:使用可靠消息+最大努力通知型,如使用RabbitMQ或者RocketMQ等



