《我想进大厂》之分布式事务篇(二)
SAGA
Saga源于1987 年普林斯顿大学的 Hecto 和 Kenneth 发表的如何处理 long lived transaction(长活事务)论文。
主要思想就是将长事务拆分成多个本地短事务。
如果全部执行成功,就正常完成了,反之,则会按照相反的顺序依次调用补偿。
SAGA模式有两种恢复策略:
向前恢复,这个模式偏向于一定要成功的场景,失败则会进行重试
向后恢复,也就是发生异常的子事务依次回滚补偿
由于这个模式在国内基本没看见有谁用的,不在赘述。
消息队列
基于消息队列来实现最终一致性的方案,这个相比前面的我个人认为还稍微靠谱一点,那些都是理论啊,正常生产的实现很少看见应用。
基于消息队列的可能真正在应用的还稍微多一点。
一般来说有两种方式,基于本地消息表和依赖MQ本身的事务消息。
本地消息表的这个方案其实更复杂,实际上我也没看到过真正谁来用。这里我以RocketMQ的事务消息来举例,这个方式相比本地消息表则更完全依赖MQ本身的特性做了解耦,释放了业务开发的复杂工作量。
- 业务发起方,调用远程接口,向MQ发送一条半事务消息,MQ收到消息之后会返回给生产者一个ACK
- 生产者收到ACK之后,去执行事务,但是事务还没有提交。
- 生产者会根据事务的执行结果来决定发送commit提交或者rollback回滚到MQ
- 这一点是发生异常的情况,比如生产者宕机或者其他异常导致MQ长时间没有收到commit或者rollback的消息,这时候MQ会发起状态回查。
- MQ如果收到的是commit的话就会去投递消息,消费者正常消费消息即可。如果是rollback的话,则会在设置的固定时间期限内去删除消息。
这个方案基于MQ来保证消息事务的最终一致性,还算是一个比较合理的解决方案,只要保证MQ的可靠性就可以正常实施应用,业务消费方根据本身的消息重试达到最终一致性。
框架
以上说的都是理论和自己实现的方式,那么分布式事务就没有框架来解决我们的问题吗?
有,其实还不少,但是没有能扛旗者出现,要说有,阿里的开源框架Seata还有阿里云的GTS。
GTS(Global Transaction Service 全局事务服务)是阿里云的中间件产品,只要你用阿里云,付钱就可以用GTS。
Seata(Simple Extensible Autonomous Transaction Architecture)则是开源的分布式事务框架,提供了对TCC、XA、Saga以及AT模式的支持。
那么,GTS和Seata有什么关系呢?
实际上最开始的时候他们都是基于阿里内部的TXC(Taobao Transaction Constructor)分布式中间件产品,然后TXC经过改造上了阿里云就叫做GTS。
之后阿里的中间件团队基于TXC和GTS做出了开源的Seata,其中AT(Automatic Transaction)模式就是GTS原创的方案。
至于现在的版本,可以大致认为他们就是一样的就行了,到2020年,GTS已经全面兼容了Seata的 GA 版本。
图片来自阿里云官网GTS
整个GTS或者Seata包含以下几个核心组件:
- Transaction Coordinator(TC):事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。
- Transaction Manager(TM):控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。
- Resource Manager(RM):控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。
无论对于TCC还是原创的AT模式的支持,整个分布式事务的原理其实相对来说还是比较容易理解。
- 事务开启时,TM向TC注册全局事务,并且获得全局事务XID
- 这时候多个微服务的接口发生调用,XID就会传播到各个微服务中,每个微服务执行事务也会向TC注册分支事务。
- 之后TM就可以管理针对每个XID的事务全局提交和回滚,RM完成分支的提交或者回滚。
核心组件定义-图片来自阿里云官网
AT模式
原创的AT模式相比起TCC的方案来说,无需自己实现多个接口,通过代理数据源的形式生成更新前后的UNDO_LOG,依靠UNDO_LOG来实现回滚的操作。
执行的流程如下:
- TM向TC注册全局事务,获得XID
- RM则会去代理JDBC数据源,生成镜像的SQL,形成UNDO_LOG,然后向TC注册分支事务,把数据更新和UNDO_LOG在本地事务中一起提交
- TC如果收到commit请求,则会异步去删除对应分支的UNDO_LOG,如果是rollback,就去查询对应分支的UNDO_LOG,通过UNDO_LOG来执行回滚
事务模式-AT-图片来自阿里云官网
TCC模式
相比AT模式代理JDBC数据源生成UNDO_LOG来生成逆向SQL回滚的方式,TCC就更简单一点了。
- TM向TC注册全局事务,获得XID
- RM向TC注册分支事务,然后执行Try方法,同时上报Try方法执行情况
- 然后如果收到TC的commit请求就执行Confirm方法,收到rollback则执行Cancel
事务模式-TCC-图片来自阿里云官网
XA模式
- TM向TC注册全局事务,获得XID
- RM向TC注册分支事务,XA Start,执行SQL,XA END,XA Prepare,然后上报分支执行情况
- 然后如果收到TC的commit请求就执行Confirm方法,收到rollback则执行Cancel
事务模式-XA-图片来自阿里云官网
SAGA模式
- TM向TC注册全局事务,获得XID
- RM向TC注册分支事务,然后执行业务方法,并且上报分支执行情况
- RM收到分支回滚,执行对应的业务回滚方法
事务模式-Saga-图片来自阿里云官网
总结
这里从事务的ACID开始,向大家先说了XA是分布式事务处理的规范,之后谈到2PC和3PC,2PC有同步阻塞、单点故障和数据不一致的问题,3PC在一定程度上解决了同步阻塞和单点故障的问题,但是还是没有完全解决数据不一致的问题。
之后说到TCC、SAGA、消息队列的最终一致性的方案,TCC由于实现过于麻烦和复杂,业务很少应用,SAGA了解即可,国内也很少有应用到的,消息队列提供了解耦的实现方式,对于中小公司来说可能是较为低成本的实现方式。
最后再说目前国内的实现框架,云端阿里云的GTS兼容Seata,非云端使用Seata,它提供了XA、TCC、AT、SAGA的解决方案,可以说是目前的主流选择。
文章转自公众号:艾小仙