前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何解决分布式事务

如何解决分布式事务

作者头像
微观技术
发布2020-08-20 15:15:01
5640
发布2020-08-20 15:15:01
举报
文章被收录于专栏:微观技术微观技术

事务有四个特性:原子性、一致性、隔离性、持久性。这四个属性通常称为 ACID

随着分布式架构理念提出,软件系统架构开始迈入一个新时代。一个臃肿的应用会拆分出若干个微服务中心,按业务域维度划分系统边界,大家各司其职,在自己负责的领域深耕细作,可谓好处多多。但同时也增加了系统复杂度,每个子业务系统都涉及数据库操作,如何解决分布式事务是一个绕不开的话题。

什么是分布式事务,一句话概括:分布式事务就是用来保证多个原子服务数据源一致性的解决方案。

常见解决方案

1、流水任务

执行业务逻辑前,先插入流水任务,如果中间过程调用外部RPC接口服务或者本地数据库操作失败时,流水任务会被定时调度任务周期性触发、重试,直到成功。前提条件,所有接口服务都要实现幂等。当执行成功时,流水记录会被删除。

当然为了缩小接口的重试范围,也可以针对局部调用失败引入局部重试流水。

优点:

•实现简单,不依赖任何外部框架

缺点:

•不支持回滚,只能不断重试直到接口成功。如果中间某一步操作因数据问题无法成功,只能重试若干次后报警人工介入。•无论全局重试、还是片段重试,都要单独处理,复杂度高

2、基于事务消息

在淘宝平台中,广泛使用分布式事务场景的方案是基于消息分布式事务,通过MQ事务消息功能特性达到分布式事务的最终一致性。

•MQ发送方执行第一个本地事务前,会向MQ服务端发送一条消息,但这条消息不同于普通MQ消息,而是一条事务消息。事务消息在MQ的服务端处于一个特殊的状态,此时消息已经保存到MQ服务端,但MQ订阅方是无法感知到该条消息,并且不会进行消费。•完成事务消息的发送后,开始执行本地的数据库事务操作,并根据执行结果走提交或回滚•如果本地事务执行后,因为某些原因没有及时给MQ服务端相应的反馈,MQ服务端会向业务处理服务询问消息状态,业务处理服务根据消息ID或者消息内容确认该消息是否有效。

•如果发现本地事务没有执行,则给MQ服务端返回结果,告知MQ服务端可废弃该事务消息。•如果检查发现本地事务已经实际已经成功执行了,则MQ服务端的消息为正常状态。

消息订阅方获取到正常消息后,执行第二个本地事务。如果第二个本地事务执行成功,则最终实现两个不同数据库上的事务同时成功。如果失败,借助MQ框架自身的重试机制,多次重试,实现数据的最终一致性。

3、两阶段提交

•准备阶段

•协调者向所有的参与者发送事务执行请求,并等待参与者反馈事务执行结果。 •事务参与者收到请求之后,本地执行事务,但不提交。 •参与者将自己事务执行情况反馈给协调者,同时等待协调者的下一步通知。

•提交阶段

•根据准备阶段的结果,执行commit或rollback

缺点:

•第一步的数据库事务要等待第二阶段的反馈才能提交,事务锁占用时间较长,会拉低系统的吞吐量。

淘宝很多业务线有一种变种玩法,也是基于两阶原理,但是耦合性做了弱化。

•引入状态机。分为:初始化、上架、失效、删除 等多种状态。当然结合具体业务场景,可能还会有更多业务状态。•接口服务拆成两部分:

•首次调用,数据库中插入业务数据,但行记录状态标记为 init(初始化状态对外不可见)

•待所有依赖的RPC接口全部调用一轮,所有接口的数据全部初始化 •然后开始第二轮调用,将状态置为对外可见。当然,此阶段可能会部分调用失败,需要多次重试

如果一个业务逻辑内部涉及多次RPC调用以及本地数据库事务,如何保证数据的全局统一性?还有一种解决方案!

•表结构增加一个字段,引入目标状态。在调用链路的最上层先给目标状态赋值•然后依次调用外部RPC接口,以及更新本地数据库•最后修改本地记录状态的值,并将目标状态值清空

4、三阶段提交

第一阶段:CanCommit

协调者向参与者发送事务执行请求CanCommit,参与者如果可以提交就返回YES响应,否则就返回NO响应。

第二阶段:PreCommit

协调者根据参与者反馈的结果来决定是否继续执行事务的PreCommit操作,根据协调者反馈的结果,有以下两种可能:

1、假如协调者收到参与者的反馈结果都是YES,那么就会执行PreCommit操作。

•协调者向参与者发送PreCommit请求,并进入Prepared阶段。•参与者接收到PreCommit请求后,执行事务操作,但不提交•事务操作执行成功,则返回ACK响应,然后等待协调者的下一步通知。

2、假如有任何一个参与者向协调者发送了NO响应,或者等待超时之后,协调者没有收到参与者的响应,那么就中断事务。

•协调者向所有参与者发送中断请求。•参与者收到中断请求之后(或超时之后,仍未收到协调者的请求),执行事务中断操作。

第三阶段:DoCommit

1、执行提交

•协调者收到ACK之后,向所有的参与者发送DoCommit请求。•参与者收到DoCommit请求之后,提交事务。•事务提交之后,向协调者发送ACK响应。•协调者收到ACK响应之后,完成事务。

2、中断事务

•在第二阶段,协调者没有收到参与者发送的ACK响应,那么就会执行中断事务。

5、TCC 模式

TCC方案分为Try Confirm Cancel三个阶段,属于补偿性分布式事务。

Try:尝试待执行的业务

这个过程并未执行业务,只是完成所有业务的一致性检查,并预留好执行所需的全部资源

Confirm:执行业务

这个过程真正开始执行业务,由于Try阶段已经完成了一致性检查,因此本过程直接执行,而不做任何检查。并且在执行的过程中,会使用到Try阶段预留的业务资源。

Cancel:取消执行的业务

若业务执行失败,则进入Cancel阶段,它会释放所有占用的业务资源,并回滚Confirm阶段执行的操作。

以一个电商系统用户购买商品的流水线为例。

Try阶段:

在Try阶段成功之后进入Confirm阶段,如有任何异常,进入Cancel阶段。

Confirm阶段:

Cancel阶段:

假设库存扣减失败,此时需要回滚事务

TCC方案适用于一致性要求极高的系统,比如金钱、交易相关,基于补偿的原理,因此,需要编写大量的补偿代码,比较冗余。市面可以参考的开源TCC框架,比如TCC-transaction。

6、GTS(开源项目名:Seata)

地址:https://github.com/seata/seata

GTS 把分布式事务定义为由若干本地事务(分支)组成的全局事务。被全局事务管理的全部分支,将在协调器的协调下,保证一起成功或一起回滚。

GTS 定义了一个事务模型,把整个全局事务过程模型化为 TM、RM、TC 三个组件之间协作的机制。

•Transaction Coordinator (TC):事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。•Transaction Manager (TM):控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。•Resource Manager (RM):控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。

执行过程:

•TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID。•XID 在微服务调用链路的上下文中传播。•RM 向 TC 注册分支事务,将其纳入 XID 对应全局事务的管辖。•TM 向 TC 发起针对 XID 的全局提交或回滚决议。•TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。

GTS 的 JDBC 数据源代理通过对业务 SQL 的解析,把业务数据在更新前的数据镜像组织成回滚undo日志,执行SQL,并得到redo日志,利用 本地事务 的 ACID 特性,将业务数据的更新和回滚日志的写入在同一个 本地事务 中提交。这样可以保证:任何提交的业务数据的更新一定有相应的回滚日志存在。

参考文章: 分布式事务 GTS 的价值和原理浅析

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-01-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 微观技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 常见解决方案
  • 1、流水任务
  • 2、基于事务消息
  • 3、两阶段提交
  • 4、三阶段提交
  • 5、TCC 模式
  • 6、GTS(开源项目名:Seata)
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档