分布式事务

分布式事务

1、什么是分布式事务

针对于单数据库的事务我们叫本地事务/传统事务,在分布式环境中一个请求可能涉及到多个数据库的写操作(多数据源),要保证多数据源的一致性必须用到分布式事务。

2、为什么需要分布式事务

系统微服务化后,一个看似简单的功能,内部可能需要调用多个服务并操作多个数据库实现,服务调用的分布式事务问题变的非常突出。
分布式事务

一个下单请求同时设计到订单库,优惠券库,库存库的写操作,需要保证三个库写操作的一致性,就要用到分布式事务 即:分布式事务就是要解决一个请求同时对多个数据库写操作的一致性

注意:微服务拆分原则,尽量让大部分操作都不要跨微服务操作,也就是跨库。 分布式事务比本地事务耗费的资源更多。

3、常见的分布式事务解决方案

针对不同的分布式场景,业界常见的解决方案有2PC、TCC、 可靠消息最终一致性、最大努力通知这几种。

3.1、什么是2pc

2PC即两阶段提交协议,是将整个事务流程分为两个阶段,准备阶段( Prepare phase).提交阶段( commit phase ) , 2是指两个阶段, P是指准备阶段, C是指提交阶段。

2pc成功情况

2pc失败情况

在第一阶段(准备阶段),事务管理器先向事务参与者(资源)们发送准备请求,大家都返回OK状态,那么就进入第二阶段,提交事务,如果在第一阶段有任何一个参与者没有OK,那么事务协调器通知其他所有事务参与者(资源)回滚事务。2PC常见的标准是XA, JTA,Seata等。

二阶段能保证分布式事务的原子性,但是也有一些明显的缺陷。比如:

①在第一阶段,如果参与者迟迟不回复协调者,就会造成事务的阻塞,性能不好。

②单节点故障,如果协调器挂了,参与者会阻塞。比如在第二阶段,如果事务协调器宕机,参与者没办法回复信息,长时间处于事务资源锁定,造成阻塞(事务操作需要加锁)。

③在第二阶段,如果在事务协调器发出"commit"执行后宕机。一部分参与者收到了消息提交了事务,而一部分没有收到消息没法做出事务提交操作,这样就出现了数据不一致。

④在第二阶段,如果事务事务协调器发出“commit”指令后宕机,收到“commmit”指令的参与者也宕机了, 那么事务最终变成了什么效果,提交了还是没提交?没有谁知道。

3.1.1、基于XA协议的两阶段提交方案

2PC的传统方案是在数据库层面实现的,如Oracle、MySQL都支持2PC协议,为了统一标准,减少行业内不必要的对接成本,需要制定标准化的处理模型及接口标准,国际开放标准组织Open Group定义了分布式事务处理模型DTP ( Distributed Transaction Processing Reference Model )。

DTP模型

DTP模型定义如下角色

①AP(Application Program) :即应用程序,可以理解为使用DTP分布式事务的程序。

②TM(Transaction Manager) :事务管理器,负责协调和管理事务,事务管理器控制着全局事务,管理事务生命周期,并协调各个RM。

③RM(Resource Manager) :即资源管理器,可以理解为事务的参与者。一般情况下是指一个数据库实例,通过资源管理器对该数据库进行控制。资源管理器控制着分支事务。

全局事务是指分布式事务处理环境中,需要操作多个数据库共同完成一个工作,这个工作即是一个全局事务。

DTP模型定义TM和RM之间通讯的接口规范叫XA ,简单理解为数据库提供的2PC接口协议,基于 数据库的XA协议来实现2PC又称为XA方案。

以上三个角色之间的交互方式如下:

①TM向AP提供应用程序编程接口, AP通过TM提交及回滚事务。

②TM交易中间件通过XA接口来通知RM数据库事务的开始、结束以及提交、回滚等。

以以上案例为例,其执行流程如下:

应用程序( AP )持有用户库和积分库两个数据源(RM)。

1、应用程序( AP )通过TM通知用户库RM新增用户,同时通知积分库RM为该用户新增积分。RM此时并未提交事务,此时用户和积分资源锁定。

2、TM收到执行回复,只要有一方执行失败,则分别向其他RM发起回滚事务,回滚完毕,资源锁释放。

或者TM收到执行回复,全部成功,此时向所有RM发起提交事务,提交完毕,资源锁释放。

XA方案的问题

①需要本地数据库支持XA协议。Mysql5.7及以后才支持 oracle。

②资源锁需要等到两个阶段结束才释放,性能较差。

3.1.2、Seata的两阶段提交方案

Seata是由阿里中间件团队发起的开源项目Fescar ,后更名为Seata 。它是一个开源的分布式事务框架,传统2PC的问题在Seata中得到了解决。它通过对本地关系数据库的分支事务的协调,来驱动完成全局事务,是工作在应用层的中间件。主要优点是性能较好,且不长时间占用连接资源。它以高效并且对业务0侵入的方式,解决微服务场景下面临的分布式事务问题。它目前提供AT模式(即2PC)及TCC模式的分布式事务解决方案。

Transaction Coordinator(TC):事务协调器,它是独立的中间件,需要独立部署运行。它维护全局事务的运行状态,接收TM指令发起全局事务的提交与回滚,负责与RM通信协调各各分支事务的提交或回滚。 相当于是一个软件,需要单独部署。

Transaction Manager ™:事务管理器, TM需要嵌入应用程序中工作。它负责开启一个全局事务,并最终向TC发起全局提交或全局回滚的指令。

Resource Manager (RM):控制分支事务, 负责分支注册、状态汇报,并接收事务协调器TC的指令, 驱动分支(本地)事务的提交和回滚。

案例:注册用户送积分

注册用户送积分,分布式事务案例

具体的执行流程如下:

1、用户服务的TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID。

2、用户服务的RM向TC注册分支事务,该分支事务在用户服务执行新增用户逻辑,并将其纳入XID对应 全局事务的管辖。

3、用户服务执行分支事务,向用户表插入一条记录。

4、逻辑执行到远程调用积分服务时(XID在微服务调用链路的上下文中传播)。积分服务的RM向TC注册分支事务,该分支事务执行增加积分的逻辑,并将其纳入XID对应全局事务的管辖。

5、积分服务执行分支事务,向积分记录表插入一条记录,执行完毕后,返回用户服务。

3.1.3、Seata实现2PC与传统2PC的差别

架构层次方面,传统2PC方案的RM实际上是在数据库层, RM本质上就是数据库自身,通过XA协议实现。而Seata的RM是以jar包的形式作为中间件层部署在应用程序这一侧的。

两阶段提交方面,传统2PC无论第二阶段的决议是commit还是rollback ,事务性资源的锁都要保持到Phase2完成才释放。而Seata的做法是在Phase1就将本地事务提交,这样就可以省去Phase2持锁的时间,整体提高效率。

3.2、TCC

TCC(Try-Confirm-Cancle), 是基于补偿型事务的AP系统的一种实现, 具有弱一致性。

补偿理解:按照事先预定的方案去执行,如果失败了就走补偿方案(撤销)。

分布式事务解决方案TCC

事务开始时,业务应用会向事务协调器注册启动事务。之后业务应用会调用所有服务的try接口,完成一阶段准备。之后事务协调器会根据try接口返回情况,决定调用confirm接口或者cancel接口。如果接口调用失败,会进行重试。

3.2.1、常见解决方案

目前市面上的TCC框架众多比如下面这几种:

TCC框架

Seata也支持TCC,现在支持了springcloud。

3.2.2、优缺点

1、优点: 异步执行效率高

TCC能够对分布式事务中的各个资源进行分别锁定, 分别提交与释放。例如, 假设有AB两个操作, 假设A操作耗时短, 那么A就能较快的完成自身的try-confirm-cancel流程, 释放资源. 无需等待B操作。如果事后出现问题, 追加执行补偿性事务即可。

TCC是绑定在各个子业务上的(除了cancle中的全局回滚操作), 也就是各服务之间可以在一定程度上”异步并行”执行。

2、缺点:

对应用的侵入性强。业务逻辑的每个分支都需要实现try、confirm、cancel三个操作,应用侵入性较强,改造成本高。实现难度较大。需要按照网络状态、系统故障等不同的失败原因实现不同的回滚策略。为了满足一致性的要求,confirm和cancel接口必须实现幂等(一个操作多次循环都是一样)。

注意:

事务管理器(协调器)这个节点必须以带同步复制语义的高可用集群(HAC)方式部署。

事务管理器(协调器)还需要使用多数派算法来避免集群发生脑裂问题。 脑裂(brain-split):脑裂是指在主备切换时,由于切换不彻底或其他原因,导致客户端和Slave误以为出现两个active master,最终使得整个集群处于混乱状态 。

使用场景:严格一致性、执行时间短、实时性要求高。举例: 红包, 收付款业务。

3.3、可靠消息最终一致性

可靠消息最终一致性方案,是指当事务发起方执行完成本地事务后发出一条消息,事务参与方(消息消费者)一定能够接收消息并处理事务成功。此方案强调的是只要消息发给事务参与方,最终事务要达到一致。

此方案是利用消息中间件完成,如下图:

可靠消息最终一致性解决方案

3.3.1、要解决的问题

最终一致性要解决三个问题:本地事务和消息发送的原子性,接收消息的可靠性,消息重复消费。

1) 本地事务和消息发送原子性

本地事务与消息发送的原子性问题:事务发起方在本地事务执行成功后,消息必须发出去,否则就丢弃消息。即实现本地事务和消息发送的原子性,要么都成功,要么都失败。本地事务与消息发送的原子性问题是实现可靠消息最终一致性方案的关键问题。

①.Begin transaction

②.发送MQ

③.数据库操作

④.Commit transation;

  1. 事务参与方接收消息可靠性 ack机制。事务参与方必须能够从消息队列接收到消息,如果接收消息失败可以重复接收消息。

  2. 消息重复消息问题,幂等性校验。

由于网络2的存在,若某一个消费节点超时但是消费成功,此时消息中间件会重复投递此消息,就导致了消息的重复消费。要解决消息重复消费的问题就要实现事务参与方的方法幂等性。

3.3.2、本地消息表方案

本地消息表这个方案最初是eBay提出的。此方案的核心是通过本地事务保证数据业务操作和消息的一致性,然后通过定时任务将消息发送至消息中间件,待确认消息发送给消费方成功,再将消息删除。

本地消息表方案

优点:简单。

缺点:要创建很多本地消息表。

3.3.3.RocketMQ方案

RocketMQ是一个来自阿里巴巴的分布式消息中间件 ,于2012年开源,并在2017年正式成为Apache顶级项目。据了解,包括阿里云上的消息产品以及收购的子公司在内,阿里集团的消息产品全线都运行在RocketMQ之上,并且最近几年的双十一大促中, RocketMQ都有抢眼表现。Apache RocketMQ 4.3之后的版本正式支持事务消息,为分布式事务实现提供了便利性支持。

RocketMQ事务消息设计则主要是为了解决Producer端的消息发送与本地事务执行的原子性问题,

RocketMQ的设计中broker与producer端的双向通信能力,使得broker天生可以作为一个事务协调者存在。而RocketMQ本身提供的存储机制为事务消息提供了持久化能力。RocketMQ的高可用机制以及可靠消息设计则为了事务消息在系统发生异常时依然能够保证达成事务的最终一致性。在RocketMQ 4.3后实现了完整的事务消息,实际上是对本地消息表的一个封装,将本地消息表移动到了MQ内部,解决Producer端的消息发送与本地事务执行的原子性问题。

Rocket MQ方案解决可靠消息最终一致性

执行步骤如下:

①MQ发送方发送远程事务消息到MQ Server。

②MQ Server给予响应, 表明事务消息已成功到达MQ Server。

③ MQ发送方接收到响应,Commit本地事务。

④ 若本地事务Commit成功, 则通知MQ Server允许对应事务消息被消费; 若本地事务失败, 则通知MQ Server对应事务消息应被丢弃。

⑤ 若MQ发送方超时未对MQ Server作出本地事务执行状态的反馈, 那么需要MQ Servfer向MQ发送方主动回查事务状态, 以决定事务消息是否能被消费。

⑥ 当得知本地事务执行成功时, MQ Server允许MQ订阅方消费本条事务消息。

需要额外说明的一点, 就是事务消息投递到MQ订阅方后, 并不一定能够成功执行,需要MQ订阅方主动给予消费反馈(ack)。

如果MQ订阅方执行远程事务成功, 则给予消费成功的ack, 那么MQ Server可以安全将事务消息移除;

如果执行失败, MQ Server需要对消息重新投递, 直至消费成功。

主流MQ对比

特性ActiveMQRabbitMQRocketMQkafka
开发语言JavaErlangJavaScala
单机吞吐量万级万级10万级10万级
时效性Ms级Us级Ms级Ms级别以内
可用性高(主从架构)高(主从架构)非常高(分布式架构)非常高(分布式架构)
功能特性老牌产品,很多公司得到应用基于erlang开发,并发能力强,性能好,管理界面丰富MQ功能完善,扩展性佳只支持主要的MQ功能,大数据领域应用广泛

注意事项

①消息中间件在系统中扮演一个重要的角色, 所有的事务消息都需要通过它来传达, 所以消息中间件也需要支持 ack 来确保事务消息不丢失。

②根据业务逻辑的具体实现不同,还可能需要对消息中间件增加消息不重复, 不乱序等其它要求。

适用场景

①执行周期较长。

②实时性要求不高。

例如:

①跨行转账/汇款业务(两个服务分别在不同的银行中)。

②退货/退款业务。

③财务, 账单统计业务(先发送到消息中间件, 然后进行批量记账)。

3.4、最大努力通知

最大努力通知服务表示在不影响主业务的情况下,尽可能地确保数据的一致性。它需要开发人员根据业务来指定通知规则,在满足通知规则的前提下,尽可能的确保数据的一致,以达到最大努力的目的。

最大努力通知支付宝三方支付接口回调

目标:发起通知方(接口提供方)通过一定的机制最大努力将业务处理结果通知到接收方(接口调用方)。

具体包括:

①有一定的消息重复通知机制。因为接收通知方可能没有接收到通知,此时要有一定的机制对消息重复通知。 10s 1min 10min 1h 5h 1d。

②消息校对机制。如果尽最大努力也没有通知到接收方,或者接收方消费消息后要再次消费,此时可由接收方主动向通知方查询消息信息来满足需求。

③消息处理方需要保证幂等性。

场景:支付宝结果通知。

最大努力通知与可靠消息一致性有什么不同

①可靠消息最终一致性。系统A本地事务执行成功,通知系统B处理任务,通常通过MQ实现。一般适用于平台内部,对一 致性要求相对较高(微服务的2个子系统之间)。

②最大努力通知。所谓最大努力通知就是系统A用最大努力通知系统B,能不能成功,不做完全保证,如果没通知到位,系统B可以主动来调用系统A的接口查询结果状态。一般适用于跨平台业务,或对接了上方平台的业务场景(支付结果通知)。

③消息处理方需要保证幂等性。

场景:支付宝结果通知。

最大努力通知与可靠消息一致性有什么不同

①可靠消息最终一致性。系统A本地事务执行成功,通知系统B处理任务,通常通过MQ实现。一般适用于平台内部,对一 致性要求相对较高(微服务的2个子系统之间)。

②最大努力通知。所谓最大努力通知就是系统A用最大努力通知系统B,能不能成功,不做完全保证,如果没通知到位, 系统B可以主动来调用系统A的接口查询结果状态。一般适用于跨平台业务,或对接了上方平台的业务场景(支付结果通知)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值