分布式事务解决方案
如何解决分布式一致性问题
1.查询模式:
任何事务操作都需要提供一个查询接口,用来向外部输出操作执行的状态。事务操作的使用方可以通过查询接口得知事务操作执行的状态,然后根据不同的状态来做不同的处理操作。
2.补偿模式:
通过查询模式,可以知道事务操作的状态,如果操作处于错误的状态,就需要对其未完成的子操作进行修复,来让系统达到一致。这种后期通过努力让系统最终达到一致的操作就叫做补偿。
3.异步确保模式:
异步确保模式是使用补偿模式一个经典例子。在高并发的场景下,把使用方对响应时间要求不高的操作从主流程中摘除,通过异步的方式进行处理,将操作封装后持久化到数据库,然后定时捞取未完成的操作进行补偿模式。
4.定期校对模式:
系统中各节点之间可能存在不一致,就需要定期执行校对操作,如果发现不一致,则运用补偿模式,进行补偿操作,来使系统最终达到一致。
分布式一致性协议
1.两阶段提交协议(2PC):
在分布式事务中,一个事务贯穿多个节点,每个节点仅仅知道自己操作的结果,但是并不知道其它节点的操作结果。为了保证事务的一致性,就需要一个统一的协调者,每个节点把操作的结果告知协调者,协调者再根据操作结果再通知各节点是将操作提交还是取消操作,下图是执行成功的示例:
两阶段提交协议有准备阶段和提交阶段两个阶段,可以保证强一致性,但是复杂,不够灵活,而且还有以下缺点:阻塞(每个节点必须收到响应才会继续向下执行,否则则一直处于阻塞状态,占用资源),节点故障(如果在执行事务的过程中有节点发生故障,则协调者只能等待,会阻塞其他节点资源,而如果发生这种情况后,协调者也发生故障,新选取的协调者无法处理这种情况)。
2.三阶段提交协议(3PC):
三阶段提交协议是两阶段提交协议的改进,目的是解决两阶段协议的缺点。它加入了超时机制来解决两阶段协议的阻塞问题,并在准备阶段前增加了询问阶段(协调者询问节点是否可以提交,节点只需要返回是或否即可)。如果发生响应超时的问题,则可以回滚,不会使节点进入阻塞状态等待。
三阶段提交协议的缺点是需要更多的通讯次数,实现比较复杂。两阶段提交协议和三阶段提交协议都是强一致性的分布式事务解决方案。
上文也提到过分布式一致性协议,2pc和3pc都是不是完美的。
分布式事务解决方案(包含强一致性分布式解决方案和最终一致性解决方案)
1.基于XA协议的两阶段提交方案(强一致性分布式解决方案)
两阶段提交方案应用非常广泛,几乎所有商业OLTP数据库都支持XA协议。但是两阶段提交方案锁定资源时间长,对性能影响很大,基本不适合解决微服务事务问题。
3.三阶段提交方案(强一致性分布式解决方案)
优点:相比二阶段提交,三阶段提交降低了阻塞范围,在等待超时后协调者或参与者会中断事务。避免了协调者单点问题。阶段 3 中协调者出现问题时,参与者会继续提交事务。
缺点:数据不一致问题依然存在,当在参与者收到 preCommit 请求后等待 do commite 指令时,此时如果协调者请求中断事务,而协调者无法与参与者正常通信,会导致参与者继续提交事务,造成数据不一致。
3. TCC方案 (最终一致性解决方案)
在电商、金融领域落地较多。TCC方案其实是两阶段提交的一种改进。其将整个业务逻辑的每个分支显式的分成了Try、Confirm、Cancel三个操作。Try部分完成业务的准备工作,confirm部分完成业务的提交,cancel部分完成事务的回滚。
TCC方案让应用自己定义数据库操作的粒度,使得降低锁冲突、提高吞吐量成为可能。 当然TCC方案也有不足之处,集中表现在以下两个方面:
- 对应用的侵入性强。业务逻辑的每个分支都需要实现try、confirm、cancel三个操作,应用侵入性较强,改造成本高。
- 实现难度较大。需要按照网络状态、系统故障等不同的失败原因实现不同的回滚策略。为了满足一致性的要求,confirm和cancel接口必须实现幂等。
上述原因导致TCC方案大多被研发实力较强、有迫切需求的大公司所采用。微服务倡导服务的轻量化、易部署,而TCC方案中很多事务的处理逻辑需要应用自己编码实现,复杂且开发量大。
4.基于消息的最终一致性方案
消息一致性方案是通过消息中间件保证上、下游应用数据操作的一致性。基本思路是将本地操作和发送消息放在一个事务中,保证本地操作和消息发送要么两者都成功或者都失败。下游应用向消息系统订阅该消息,收到消息后执行相应操作。
消息方案从本质上讲是将分布式事务转换为两个本地事务,然后依靠下游业务的重试机制达到最终一致性。基于消息的最终一致性方案对应用侵入性也很高,应用需要进行大量业务改造,成本较高。
5.最大努力通知(最终一致性解决方案)
最大努力通知是一种简单的分布式事务最终一致性解决方案,适用于时间敏感度低的业务,且被动方的处理结果不会影响到主动方。
通过下图可以简单的了解一下最大努力通知的执行过程:
由上图可以看出最大努力通知分为以下三步:
(1)主动方执行完业务之后,将消息发送给消息系统。
(2)消息系统将消息通知给被动方,被动方执行成功后响应给消息系统,事务执行成功。(如果消息系统通知消息失败,则重复通知,失败超过一定次数后则不再通知,消息丢失)
(3)被动方根据定时策略主动向主动方发起校对查询,对丢失的消息进行恢复。
最大努力通知的解决方案在事务的执行过程中,消息的传递允许发生丢失,所以消息是不可靠的;被动方根据定时策略,采用补偿模式,主动向主动方发起校对查询(主动方提供校对查询接口),恢复丢失的业务消息。
6.分布式事务解决方案的框架
LCN:
https://www.jianshu.com/p/73beee3c70e9
ByteTCC:
DogTCC
https://github.com/sunpengChina/dog
DogTcc是一个2019年3月开源的,基于注解的高性能 分布式事务 TCC框架。感谢于他的框架设计,可达到2ms/事务,支持链式调用,损耗线性增长。
框架特性
- 高速,事务发起方损耗 2.15ms每事务,事务被调方损耗 2.13ms每事务
- 损耗随事务链变宽[A 调用B,C,D,E…],或者变深[A 调用B,B调用C,C调用D…],线性增长
- 对原有服务无侵入,标注是基于方法而不是RPC接口的,可以在需要回滚的最小单位方法上添加标注
- 框架自动实现幂等
- 框架实现分布式环境下的可重入锁
- 易用性高,使用者通过标注,和实现指定的回滚和确认接口,即可集成框架
- 节点无本地状态,部署多台即可实现集群,无需多余配置
- 和协议无关,使用者只要实现事务的协议注入即可集成到框架中,可参照Spring模块
- 和消息服务器无关,框架提供了消息服务接口,使用者可使用其他消息中间件,可参考zookeeper模块
- 支持事务链,事务链长度不影响事务性能
- 故障恢复,任何服务节点丢失都不会影响最终一致性,丢失节点的事务会被同类节点托管,或者在丢失节点启动时候恢复
- 错误通知,对于极端情况,Confirm或者Cancel失败,系统会通过第三方接口通知,用户需要实现该接口定义的方法
SETA:
https://github.com/seata/seata
SETA演进历史
TXC:Taobao Transaction Constructor,阿里巴巴中间件团队自 2014
年起启动该项目,以满足应用程序架构从单一服务变为微服务所导致的分布式事务问题。
GTS:Global Transaction Service,2016 年 TXC 作为阿里中间件的产品,更名为 GTS 发布。
FESCAR:2019 年开始基于 TXC/GTS 开源 FESCAR。
后更名为Seata