什么是分布式事务以及有哪些解决方案?

一、什么是分布式事务?

答:指一次大的操做由不一样的小操做组成的,这些小的操做分布在不一样的服务器上,分布式事务须要保证这些小操做要么所有成功,要么所有失败。从本质上来讲,分布式事务就是为了保证不一样数据库的数据一致性。html

二、分布式事务产生的缘由?

2.1 数据库分库分表

   当数据库单表数据达到千万级别,就要考虑分库分表,那么就会从原来的一个数据库变成多个数据库。例如若是一个操做即操做了01库,又操做了02库,并且又要保证数据的一致性,那么就要用到分布式事务。sql

2.2 应用SOA化

   所谓的SOA化,就是业务的服务化。例如电商平台下单操做就会产生调用库存服务扣减库存和订单服务更新订单数据,那么就会设计到订单数据库和库存数据库,为了保证数据的一致性,就须要用到分布式事务。数据库

总结:其实上面两种场景,归根究竟是要操做多数据库,而且要保证数据的一致性,而产生的分布式事务的。服务器

三、分布式事务解决方案

3.1 两阶段提交(2PC)

   XA是一个分布式事务协议,由Tuxedo提出。XA中大体分为两部分:事务管理器和本地资源管理器。其中本地资源管理器每每由数据库实现,好比Oracle、Mysql等数据库都实现了XA接口,而事务管理器做为全局的调度者,负责各个本地资源的提交回滚。网络

XA实现分布式事务的原理以下:并发

分布式事务-2PC原理图

总结

  二阶段提交看起来确实可以提供原子性的操做,可是它存在几个缺点:分布式

一、同步阻塞问题:执行过程当中,全部参与节点都是事务阻塞型的。当参与者占有公共资源时,其余第三方节点访问公共资源不得不处于阻塞状态。高并发

二、单点故障:因为(事务管理器)协调者的重要性,一旦协调者发生故障。(本地资源管理器)参与者会一直阻塞下去。尤为在第二阶段,协调者发生故障,那么全部的参与者还都处于锁定事务资源的状态中,而没法继续完成事务操做。(若是是协调者挂掉,能够从新选举一个协调者,可是没法解决由于协调者宕机致使的参与者处于阻塞状态的问题)性能

三、数据不一致:在二阶段提交的阶段二中,当协调者向参与者发送commit请求以后,发生了局部网络异常或者在发送commit请求过程当中协调者发生了故障,这会致使只有一部分参与者接收到了commit请求。而在这部分参与者接到commit请求以后就会执行commit操做。可是其余部分未接到commit请求的机器没法执行事务提交。因而整个分布式系统便出现了数据不一致的现象。优化

四、二阶段没法解决的问题:参与者在发出commit消息以后宕机,而惟一接收到这条消息的协调者同时也宕机了。那么即便协调者经过选举协议产生了新的协调者,这条事务的状态也是不肯定的,没人知道事务是否被已经提交了。

3.2 三阶段提交(3PC)

  3PC其实在2PC的基础上增长了CanCommit阶段,是2PC的变种,并引入了超时机制。一旦事务参与者迟迟没有收到协调者的Commit请求,就会自动进行本地commit,这样相对有效的解决了协调者单点故障的问题。可是,性能和数据一致性问题没有根本解决。

3PC分为三个阶段:CanCommit、PreCommit、DoCommit

3.2.1 CanCommit阶段

  它跟2PC的 准备阶段很像,协调者向参与者发送commit请求,参与者若是能够提交就返回Yes响应,不然返回No响应。

  • 事务询问:协调者向参与者发送CanCommit请求。询问是否能够执行事务提交操做。而后开始等待参与者的响应
  • 响应反馈:参与者接到CanCommit请求以后,正常状况下,若是其自身认为能够顺利执行事务,则返回Yes响应,并进入预备状态。不然返回No
3.2.2 PreCommit阶段

  协调者根据参与者的响应状况来决定是否能够进行事务的PreCommit操做。根据响应状况,有如下两种可能:

  • 假如协调者从全部的参与者得到的反馈都是Yes,那么就会执行事务的与执行。
    • 发送预提交请求:协调者向参与者发送PreCommit请求,并进入Prepared阶段。
    • 事务预提交:参与者接收到PreCommit请求后,会执行事务操做,并将undo和redo信息记录到事务日志中。
    • 响应反馈:若是参与者成功的执行了事务操做,则返回ACK响应,同时开始等待最终指令。
  • 假若有任何一个参与者向协调者发送了No响应,或者等待超时,或者协调者都没有接到参与者的响应,那么就执行事务的中断。
    • 发送中断请求:协调者向全部参与者发送abort请求。
    • 中断事务:参与者收到来自协调者的abort请求以后(或超时以后,仍未收到协调者的请求),执行事务的中断。
3.2.3 doCommit阶段

  该阶段进行真正的事务提交,也能够分为如下两种状况:

  • 执行提交
    • 发送提交请求:协调接收到参与者发送的ACK响应,那么将从预提交状态进入到提交状态。并向全部参与者发送doCommit请求。
    • 事务提交:参与者接收到doCommit请求以后,执行正式的事务提交,并在完成事务提交以后释放全部事务资源。
    • 响应反馈:事务提交完以后,向协调者发送ACK响应。
    • 完成事务:协调者接收到全部参与者的ACK响应以后,完成事务。
  • 中断事务
    • 协调者没有接收到参与者发送的ACK响应(多是接受者发送的不是ACK响应,也可能响应超时),那么就会执行中断事务。
      • 发送中断请求:协调者向全部参与者发送abort请求
      • 事务回滚:参与者接收到abort请求以后,利用其在阶段二记录的undo信息来执行事务的回滚操做,并在完成回滚以后释放全部的事务资源。
      • 反馈结果:参与者完成事务回滚以后,像协调者发送ACK消息。
      • 中断事务:协调者接收到参与者反馈的ACK消息以后,执行事务的中断。
原理图以下:

分布式事务-3PC原理图

总结

  相对于2PC而言,3PC对于协调者和参与者都设置了超时时间,而2PC只有协调者才拥有超时时间机制。这个优化解决了,参与者在长时间没法与协调者节点通信的状况下,没法释放资源的问题,由于参与者自身拥有超时机制会在超时后,自动进行本地commit从而进行释放资源。而这种机制也侧面下降了整个事务的阻塞时间和范围。可是仍然没有解决数据一致性问题,即在参与者收到PreCommit请求后等待最终指令,若是此时协调者没法与参与者正常通讯,会致使参与者继续提交事务,形成数据不一致。

3.3 补偿事务(TCC)

  TCC(Try-Confirm-Cancel)又称补偿事务。它实际上与2PC、3PC同样,都是分布式事务的一种实现方案而已。它分为三个操做:

  • Try阶段:主要是对业务系统作检测及资源预留。
  • Confirm阶段:确认执行业务操做。
  • Cancel阶段:取消执行业务操做。

  TCC事务的处理流程与2PC两阶段提交相似,不过2PC一般都是在DB层面,而TCC本质上就是应用层面的2PC,须要经过业务逻辑来实现。它的优点在于,可让应用本身定义数据库操做的粒度,使得下降锁冲突、提交吞吐量。

  不过对应用的侵入性很是强,业务逻辑的每一个分支都须要实现try、confirm、cancel三个操做。

TCC原理图以下:

分布式事务-TCC原理图

3.4 消息事务+最终一致性

  所谓的消息事务就是基于消息中间件的两阶段提交,本质上是中间件的一种特殊利用,他是将本地事务和发消息放在一个分布式事务里,保证要么本地操做成功而且对外发消息成功,要么二者都失败,开源的RocketMQ就支持这一特性,具体原理以下:

分布式事务-消息事务

步骤以下:

一、:服务A向消息中间件发送一条预备消息。

二、消息中间件保存预备消息并返回成功。

三、服务A执行本地事务。

四、服务A发送提交消息给消息中间件,服务B接收到消息以后执行本地事务。

  基于消息中间件的两阶段提交每每用在高并发场景下,将一个分布式事务拆成一个消息事务(服务A的本地操做+发消息)+服务B的本地操做,其中服务B的操做由消息驱动,只要消息事务成功,那么服务A必定成功,消息也必定发出来了,这时候服务B会收到消息去执行本地操做,若是本地操做失败,消息会重投,直到服务B操做成功,这样就变相地实现了A与B的分布式事务。

以上几个步骤可能存在异常状况,如今对其进行分析:

  • 步骤一出错:则整个事务失败,不会执行服务A的本地操做。
  • 步骤二出错:则整个事务失败,不会执行服务A的本地操做。
  • 步骤三出错:须要作回滚预备消息,由服务A实现一个消息中间件的回调接口,消息中间件会不断执行回调接口,检查服务A事务执行是否执行成功,若是失败则回滚预备消息。
  • 步骤四出错:这个时候服务A的本地事务是成功的,可是消息中间件不须要回滚,其实经过回调接口,消息中间件可以检查到服务A执行成功了,这个时候其实不须要服务发提交消息了,消息中间件能够本身对消息进行提交,从而完成整个消息事务。

参考文章:

一、https://www.cnblogs.com/xifenglou/p/8440836.html

二、https://blog.csdn.net/skyie53101517/article/details/80741868

三、https://www.cnblogs.com/zcjcsl/p/7989792.html

相关文章
相关标签/搜索