博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
8种常用的分布式事务解决方案详细分析
阅读量:2490 次
发布时间:2019-05-11

本文共 4803 字,大约阅读时间需要 16 分钟。

前言

在谈分布式事务之前,我们应该清楚事务的ACID特性,单节点中是如何处理的,最终延伸出在分布式应用中的CAP理论、BASE理论,以及在这些理论下最终变化出了哪些解决方案。

事务的特性

一批数据同时成功或者同时失败,这类需求就可以简单的理解为具有事务性,也就是ACID

  • A (Atomicity, 原子性):一个事务中的所有操作要不全部成功,要不全部失败,不能出现部分成功,部分失败的情况。
  • C(Consistency,一致性):数据库设计上这个含义比较模糊,简单可以理解为财务的对账一样,两边数据的加加减减必须要能保持一致。
  • I(Isolation,隔离性):主要是针对在并发访问数据时要有一定的隔离性,在MySQL中隔离性也是分等级的,根据不同的业务需求选择不同的隔离性,主要依靠锁+MVCC来实现,隔离性越强,数据库的吞吐就越差。
  • D(Durability,持久性):事务一旦提交,数据将会保存到数据库中,此时如果数据库发生错误,也不会造成数据丢失。

单节点中如何保证事务

单节点中的事务又叫做本地事务,数据库自身已经提供了本地事务的支持,日常开发时只需要通过一个简单的@Transactional注解就可以实现本地事务,显然这种方式在多节点中并且需要交互数据时就无法适用了。

CAP理论

要处理分布式中的问题,就必须遵守CAP定理。

  • C(Consistency,强一致性):所有节点在同一时间数据都应该保持一致。

  • A(Availability,可用性):系统应该能在合理响应时间内返回合理响应(可以是正确的响应亦或是降级的响应)。

  • P(Partition tolerance,分区容错性):当遇到某个节点或网络分区故障时,其他节点应该能够保证一致性和可用性。

CAP理论的精髓就在于只能同时满足其中的两项,而P通常又是分布式系统中无法避免的事实存在,所以一般在分布式设计中都在围绕AP中做取舍、平衡,例如Zookeeper选择CP,Redis的主从架构则倾向于AP,Eureka注册中心也是AP。

BASE理论

BASE是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的结论,是基于CAP定理逐步演化而来的,其核心思想是即使无法做到强一致性(Strong consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)。

  • Basically Available(基本可用):当系统某些故障或者不可预知的情况下,允许牺牲部分可用性,保证核心服务的稳定可用。

    响应时间上的损失:正常情况下,一个在线搜索引擎需要0.5秒内返回给用户相应的查询结果,但由于出现异常(比如系统部分机房发 生断电或断网故障),查询结果的响应时间增加到了1~2秒。
    功能上的损失:正常情况下,在一个电子商务网站上进行购物,消费者几乎能够顺利地完成每一笔订单,但是在一些节日大促购物高峰的时候,由于消费者的购物行为激增,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面。

  • Soft state(软状态):是指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。

  • Eventually consistent(最终一致性):强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。

常用的分布式事务解决方案

有了前面的理论基础之后,接下来我们就可以一起来看看目前到底有哪些解决方案了

1、2PC(两阶段提交 Two Phase Commitment Protocol)

首先是最容易理解的2PC,数据库XA协议就是采用的两阶段的提交方式来处理分布式事务问题。

角色:事务协调者、资源管理者(即事务参与者)

第一阶段

准备阶段:当应用程序调用事务协调者中的提交方法时,事务协调者会向各个资源管理者发起准备提交事务的通知,资源管理者为了确保能在之后正式被要求提交事务时提交事务,或在被正式要求回滚事务时回滚事务,则会完成一系列的准备工作(比如写日志等),如果资源管理者完成了准备则回复yes,否则回复no。

第二阶段

提交阶段:事务协调者收集到所有资源管理者在一阶段的回复后,再根据回复结果再向所有资源管理者发出提交或者回滚的命令,然后所有资源管理者按照要求执行本地事务,并回复最终执行结果,一旦有任意一个资源管理者回复失败或者超时,事务协调者都会向所有资源管理者发起事务回滚的操作。

在这里插入图片描述

2PC存在的问题

  • 1、单点故障:对于事务协调者的强依赖。
  • 2、性能不足:每个参与者在整个事务执行的过程中都必须等待所有参与者,造成阻塞等待时间过长。
  • 3、数据不一致:协调者向所有参与者发送了提交指令,如果一个参与者未返回结果,那么协调者就不知道这个参与者内部到底发生了什么,有可能参与者没收到提交指令,也有可能参与者收到了指令并且执行了本地事务,但是返回响应时协调者未收到,此时协调者就不知道到底应该是让其他参与者提交还是回滚。

2、3PC(三阶段提交 Three-phase commit)

3PC的出现就是为了解决2PC中存在的问题

角色:事务协调者、资源管理者(即事务参与者)

第一阶段

CanCommit:协调者向参与者发送commit请求,参与者如果可以提交就返回YES,否则返回NO。

第二阶段

PreCommit:如果第一阶段为YES时,协调者向参与者发送PreCommit请求,参与者收到后,执行事务操作,记录相关日志,返回ACK响应,如果第一阶段为NO时,协调者向所有参与者发送abort,参与者收到abort或者等待超时,则中断事务。

第三阶段

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

处理策略

如果协调者没有收到ACK,那么则会中断事务,向所有参与者发送abort请求,参与者收到abort请求后,利用日志进行回滚,回滚完之后回复ACK。

在第三阶段时,如果参与者未收到doCommit或者abort请求时,会在等待超时之后,继续执行事务的提交(这其实是一个概率,因为当能进行第二阶段时,说明第一阶段时响应都是YES,那么大概率事务都是可以执行成功的)。

3PC和2PC比较

3PC解决了单点故障问题,和长时间阻塞等待问题,一旦进入到了第三阶段则会默认执行提交,而不会一直处于阻塞状态,但是依旧存在数据不一致的问题,如果进入第三阶段,由于网络等原因,造成协调者发出的abort请求,参与者未接收到,那么参与者等待超时后会执行commit,则造成了数据不一致,并且三阶段实现起来也比较复杂,所以实际应用较少。

3、TCC

TCC主要就是通过补偿机制来完成分布式事务,针对每一个阶段的操作都需要写一套确认或者回滚的方法。

  • Try:尝试执行,完成所有业务检查,预留业务资源。
  • Confirm:执行业务,操作预留的业务资源。
  • Cancel:取消执行,释放Try阶段预留的资源。

在这里插入图片描述

现在应该能够理解,TCC实际上就是一种尝试方案,在操作真正数据之前先尝试一下看看是否可以成功,根据尝试的结果再确认最终是提交还是回滚,尝试的数据无论如何最终都能保证结果一致,比如账户系统Try时成功了,但是积分系统失败了,那么只要通过Cancel方法回滚冻结金额到账户余额中即可。

缺点

TCC模式的缺点也很明显,需要业务上自己实现各种补偿方案,显得太多繁琐。

4、LCN

LCN本身是一款分布式事务框架,支持了LCN、TCC、TXC三种事务模式。

L(lock)

锁定事务单元

C(confirm)

确认事务模块状态

N(notify)

通知事务

角色:TxClient、TxManager

TxClient作为模块的依赖框架,提供TX-LCN的标准支持,TxManager作为分布式事务的控制方。事务发起方或者参与方都由TxClient端来控制。

LCN模式是通过代理Connection的方式实现对本地事务的操作,然后在由TxManager统一协调控制事务。当本地事务提交回滚或者关闭连接时将会执行假操作,该代理的连接将由LCN连接池管理。

核心步骤

1、创建事务组

是指在事务发起方开始执行业务代码之前先调用TxManager创建事务组对象,然后拿到事务标示GroupId的过程。

2、加入事务组

添加事务组是指参与方在执行完业务方法以后,将该模块的事务信息通知给TxManager的操作。

3、通知事务组

是指在发起方执行完业务代码以后,将发起方执行结果状态通知给TxManager,TxManager将根据事务最终状态和事务组的信息来通知相应的参与模块提交或回滚事务,并返回结果给事务发起方。

来自LCN官网的原理图。

在这里插入图片描述

特点:

  • 该模式对代码的嵌入性为低。
  • 该模式仅限于本地存在连接对象且可通过连接对象控制事务的模块。
  • 该模式下的事务提交与回滚是由本地事务方控制,对于数据一致性上有较高的保障。
  • 该模式缺陷在于代理的连接需要随事务发起方一起释放连接,增加了连接占用的时间。

5、Seata

Seata也是一款的分布式事务框架,Seata中支持的事务模式有AT、TCC、SAGA 和 XA。

seata有详细的中文官网,此处就不做过多介绍,建议大家阅读官网进行学习。

6、本地消息表

本地消息表的思路很简单,就是在本地写业务数据的同时,也写入日志数据,而这两种数据的写入放在一个本地事务中完成,通过数据库自身的事务特性来保证,之后再根据日志数据进行后续处理,是一种保证最终一致性的方案。

在这里插入图片描述

本地消息表的方式非常灵活,针对各种问题都可以处理,借助消息队列也是侧重于最终一致性的方案,支付系统只需要能够正确处理本地事件表的数据,那么最终就一定能够使数据保持一致。

缺点

使用本地消息表也是需要额外的处理每个环节中可能产生的问题,需要额外完成这些处理逻辑,事务参与者较多的情况下将会更加麻烦,并且对比其他方案,一致性的延迟时间也较长。

7、最大努力通知

最大努力通知一般是在第三方系统调用时经常采用的方式,比如做过微信,支付宝支付的应该有了解,一般支付结果并不会立即返回,而是通过回调的方式告知,如果回调失败,还会进行间断式的多次回调。

最终再开放一个查询接口,调用方也可以通过直接查询的方式来确认业务执行的状态。

此方案的原则:

  • 1、我尽最大努力的通知你结果。
  • 2、当通知不到时,我也有提供接口供你查询最终状态。

8、事务消息(RocketMQ)

RocketMQ本身就考虑到了对于分布式事务的支持,通过一种半消息的机制来实现,思路方面感觉和本地消息差不多,本地消息需要我们自己去控制事件的状态,而RocketMQ内部已经帮我们完成了。

在这里插入图片描述

异常场景:

  • 1、前3步处理失败,本地事务都未执行,所以不存在一致性问题。

  • 2、第4步处理失败,则可以回复MQ作废消息,也可以回复MQ未知状态(unkown),如果是未知状态,MQ则会回调账户系统,确认本地事务是否成功。

  • 3、从第7步开始,事务就已经与账户系统无关了,当积分系统拉取到消息以后就应该自身保证消息能够被正确的消费。

分布式事务处理总结

分布式事务处理本身就是一件比较复杂的事情,大多数处理方案还是选择最终一致性来解决分布式事务的问题,这样可以大大提高系统的吞吐量,减少阻塞等待时间,不过也要求我们需要额外注意接口幂等性的问题。

转载地址:http://qmlrb.baihongyu.com/

你可能感兴趣的文章
Arcsde表空间自动增长
查看>>
Arcsde报ora-29861: 域索引标记为loading/failed/unusable错误
查看>>
记一次断电恢复ORA-01033错误
查看>>
C#修改JPG图片EXIF信息中的GPS信息
查看>>
从零开始的Docker ELK+Filebeat 6.4.0日志管理
查看>>
How it works(1) winston3源码阅读(A)
查看>>
How it works(2) autocannon源码阅读(A)
查看>>
How it works(3) Tilestrata源码阅读(A)
查看>>
How it works(12) Tileserver-GL源码阅读(A) 服务的初始化
查看>>
uni-app 全局变量的几种实现方式
查看>>
echarts 为例讲解 uni-app 如何引用 npm 第三方库
查看>>
uni-app跨页面、跨组件通讯
查看>>
springmvc-helloworld(idea)
查看>>
JDK下载(百度网盘)
查看>>
idea用得溜,代码才能码得快
查看>>
一篇掌握python魔法方法详解
查看>>
数据结构和算法5-非线性-树
查看>>
数据结构和算法6-非线性-图
查看>>
数据结构和算法7-搜索
查看>>
数据结构和算法8-排序
查看>>