分布式事务(一)原理概览html
分布式事务(二)JTA规范java
分布式事务(四)简单样例mysql
分布式事务(六)总结提升spring
事务(数据库事务)是java开发工程师必须掌握的一项技能。又可分为本地事务和分布式事务,其中分布式事务是进阶为高级开发工程师必会的技能。本文从概念、原理、实践多角度剖析分布式事务,但愿有所收获。sql
大部分状况下,一个服务操做一个数据库,这就是本地事务,ACID特性由数据库提供支持,好比mysql innodb引擎。以下图所示(网上的图,挺好直接用):数据库
spring 提供了2种方式实现:编程
关于本地事务这里很少说,飞机票:本地事务飞机票。api
当遇到复杂业务调用时,可能会出现跨库多资源调用(一个事务管理器,多个资源)/多服务调用(多个事务管理器,多个资源),指望所有成功或失败回滚,这就是分布式事务,用以保证“操做多个隔离资源的数据一致性”。
Mysql官方对于XA事务,描述以下:
在open group官网可查到,有2个XA规范,一个是XA,一个是XA+, 其中XA+是XA的超集,新定义了通讯资源管理器CRM的协议,建议直接看XA+便可。后续分析直接以XA+ 1994版为准。官方下载连接以下:
看名字咱们就知道 XA规范是依托于DTP场景的,下面咱们分别从DTP模型、XA规范2个视角来剖析原理。
依据X/Open《Distributed Transaction Processing: Reference Model, Version 3》上的介绍,DTP模型是一种软件体系结构,它容许多个应用程序共享多个资源管理器提供的资源,并容许将它们的工做协调到全局事务中。
要深度了解DTP,先看看模型内的元素概念,以下:
介绍完模型元素,下面来看2种典型的DTP场景,一种是单应用跨库DTP,另外一种是跨应用DTP。
一个应用使用一个事务管理器TM,操做多个资源管理器RMs,以下图:
若是分布式事务须要跨多个应用,例如微服务调用,那就必须增长通信资源管理器CRMs(跨应用管理事务),以下图:
上图中使用的接口以下:
本节咱们剖析了DTP模型,以及XA接口在DTP中的做用,下面咱们来更详细的看一下XA规范。
经过上面的分析,咱们知道XA和XA+规范的使用场景,以下图所示:
下面来具体看一下XA/XA+接口定义的函数群。其中带+号的是XA+规范,不带+号的是XA规范。
TM经过xa_*()函数调用RM。当AP调用TM启动全局事务时,TM可使用xa_interface通知事务分支的RMs。AP使用RM的本机接口完成支持全局事务的工做后,TM调用xa_()函数提交或回滚分支。xa_()函数以下表所示:
RM经过ax_*()函数调用TM。全部的TMs都必须提供这些功能。这些函数容许RM动态地控制它在事务分支中的参与。此外,CRMs使用ax_interface建立事务分支,挂起或完成事务分支,并将承诺协议传播到事务分支。ax_()函数以下表所示:
关于XA/XA+的具体方法如何调用流程这里就再也不提供。有兴趣的本身看规范原文。
XA协议中有一个细节:按照OSITP标准(模型)的定义,TMs和RMs使用两阶段提交全局事务。
如上图,XA规范实现的两阶段提交流程:(下面所有翻译自XA规范原文)
阶段1:
TM要求全部RMs准备提交(或准备)事务分支。这询问RM是否可以保证提交事务分支的能力。RM可能会查询该RM内部的其余实例。CRM被要求准备它们建立的事务分支,将prepare请求发送到远程站点并接收结果。在返回失败并回滚其工做以后,RM能够丢弃事务分支的信息。
阶段2:
TM根据实际状况向全部RMs发出提交或回滚事务分支的请求。CRM被要求提交或回滚它们建立的事务分支,向远程站点发送提交或回滚请求并接收结果。全部RMs提交或回滚对共享资源的更改,而后将状态返回给TM。而后TM能够丢弃全局事务的信息。
1.只读断言
当事务分支没有更新共享资源时,这个RM会断言并响应给TM的prepare请求。也就免去了阶段2。可是,若是一个RM在全局事务的全部RMs返回prepared以前返回了只读优化,该RM释放事务上下文,例如read locks。这时候其余事务就有机会去改变这些数据(多是写锁),显然全局序列化被破坏。一样CRM也能够断言,当TM挂起或终止线程与事务分支的关联时,它不是某个特定线程中活动的事务分支的参与者。
2.一阶段提交
若是一个TM知道DTP系统中只有一个RM在修改共享资源,那么它可使用单阶段提交。即TM免去了阶段1的prepare,直接执行了阶段2的commit。
1.资源阻塞
因为协调者的重要性,一旦协调者TM发生故障。参与者RM会一直阻塞下去。尤为在第二阶段,协调者发生故障,那么全部的参与者还都处于锁定事务资源的状态中,而没法继续完成事务操做。(若是是协调者挂掉,能够从新选举一个协调者,可是没法解决由于协调者宕机致使的参与者处于阻塞状态的问题)
2.数据不一致
在阶段二,当协调者向参与者发送commit请求以后,发生了局部网络异常或者在发送commit请求过程当中协调者发生了故障,致使只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求以后就会执行commit操做。可是其余部分未接到commit请求的机器则没法执行事务提交。因而整个分布式系统便出现了数据不一致性的现象。
因为二阶段提交存在着这些缺陷,因此,研究者们在二阶段提交的基础上作了改进,提出了三阶段提交。
3PC,即Three-phase commit protocol,由一个协调者领导事务(领头人),和一组被指导的参与者(同伙)组成。协调者和参与者都有超时执行机制,以下图:
阶段1:
【协调者】接收事务请求。若是此时出现故障,协调者将停止事务,不然,协调者发送一个canCommit给全部参与者,并切换到waiting状态。
【参与者】得到了canCommit的请求,若是赞成,它将向协调者发送Yes消息并切换到prepared状态。不然它将发送No消息并停止。若是出现故障,它将移动到abort状态。
阶段2:
【协调者】在一个时间段内,接收来自全部参与者的Yes消息,向全部参与者发送preCommit消息并切换到prepared状态。若是出现故障、超时或协调者(prepared状态)接收到No消息,将停止事务并向全部参与者发送abort消息。
【参与者】收到preCommit消息,它将发送ACK消息并等待最后的提交或停止。若是接收到停止消息、失败或等待提交的超时,它将停止。
阶段3:
【协调者】在收到来自大多数参与者的确认的状况下,协调者切换到commit状态。并向全部参与者发送doCommit请求。若是协调者在等待一个参与者的ack时超时了,它将停止事务。
【参与者】参与者接收到doCommit请求以后,执行正式的事务提交,并发送ack给协调者。注:超时未收到消息,同样会提交事务!!!!
上面讲解了2pc、xa、3pc,比较以下:
协议/优缺点 | 优势 | 缺点 |
2PC | 逻辑简单,容易理解。 | 1.全程阻塞。例如:TM故障,RM阻塞资源。 2.网络故障时,部分commit,数据一致性没法保证。 |
XA(提交时使用2PC规范) | 1.只读断言 2.可进化为一阶段提交 |
全局序列化被破坏。脏读问题。 |
3PC | 引入双边超时机制,避免阻塞。 |
1.须要3次请求返回,可能会有长延迟,性能低。 2.基于失败-中止(fail-stop)模型,出现网络问题,没法恢复。 |
上面3种协议都没法解决分布式系统下的数据一致性问题,只有Paxos算法,才能完全解决该问题。paxos飞机票:底层算法系列:Paxos算法。具体实践中,为了提升可用性(性能)通常不多作到强一致性。且大批的技术先驱们已经总结出了一套理论,让咱们有理可依。
2000年7月,Eric Brewer教授在ACM PODC会议上提出CAP猜测。Brewer认为在设计一个大规模的分布式系统时会遇到三个特性:一致性(consistency)、可用性(Availability)、分区容错(partition-tolerance),而一个分布式系统最多只能知足其中的2项。2年后,麻省理工学院的Seth Gilbert和Nancy Lynch从理论上证实了CAP。以后,CAP理论正式成为分布式计算领域的公认定理。
1. 一致性(Consistency)
一致性指“all nodes see the same data at the same time”,即更新操做成功并返回客户端完成后,全部节点在同一时间的数据彻底一致,不能存在中间状态。
强一致性:全部节点在同一时间的数据彻底一致,那么称之为强一致性。
弱一致性:此外,若是容许存在部分数据不一致,那么就称之为弱一致性。
最终一致性:若是容许存在中间状态,只要求通过一段时间后,数据最终是一致的,则称之为最终一致性。
2. 可用性(Availability)
可用性是指系统提供的服务必须一直处于可用的状态,对于用户的每个操做请求老是可以在有限的时间内返回结果。
3. 分区容错性(Partition tolerance)
分区容错的意思是,节点间通讯可能失败,仍然须要可以保证对外提供知足一致性和可用性的服务。
首先咱们必须保证P(分区容错性),才能称之为一个分布式系统,所以只能在C(一致性)和A(可用性)之间寻求平衡。而前面咱们提到的X/Open XA 两阶段提交协议的分布式事务方案,强调的就是一致性。而且因为其阻塞执行效率低,且当网络出现问题时也没法真正保证数据一致性,实际应用的并很少。而基于BASE理论的柔性事务,强调的是可用性,目前大行其道,大部分互联网公司采可能会优先采用这种方案。(有的同窗问为啥不用paxos?实现过于复杂,且保证了强一致性,想想也知道性能会有损耗,因此通常也不用!)
2008年7月28日,eBay的架构师Dan Pritchett源于对大规模分布式系统的实践总结,在ACM上发表文章提出BASE理论。文章连接:https://queue.acm.org/detail.cfm?id=1394128
BASE理论是对CAP理论的延伸,核心思想是即便没法作到强一致性(Strong Consistency,CAP的一致性就是强一致性),但应用能够采用适合的方式达到最终一致性(Eventual Consistency)。
BASE是Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)三个短语的缩写。
1. 基本可用(Basically Available)
指分布式系统在出现不可预知故障的时候,容许损失部分可用性。
2. 软状态( Soft State)
指容许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的总体可用性。
3. 最终一致( Eventual Consistency)
强调的是全部的数据更新操做,在通过一段时间的同步以后,最终都可以达到一个一致的状态。
BASE理论面向的是大型高可用可扩展的分布式系统,和传统的事物ACID特性是相反的。经过牺牲强一致性来得到可用性,容许数据在一段时间内是不一致的,但最终达到一致状态。实际应用中,会在对数据库操做进行本地事务(ACID特性)+Eventually consistent最终一致性(BASE理论)结合使用。
那么如何实现分布式环境下数据的最终一致性呢?
实践中,有些高可用场景下,没必要要强一致性,只须要最终一致性便可,这在业内称呼为"柔性事务",也就是最终一致性方案,是遵循BASE理论设计出来的。
对于某些非核心service,能够采起正向重试机制。好比一个请求超时失败了,能够再重试请求几回,一直到接收到成功返回或者达到重试次数为止。注意这里要保证接口的幂等性。即屡次调用结果同样。
不少调用第三方的接口(好比征信接口,耗时比较长),接口是异步回调型。请求方发送请求后,等待第三方异步回调本身的返回结果接口。
这两种机制都是不可靠的,必要时刻能够二者相结合使用。以下图所示:
这里不讲解已支持分布式事务的MQ.
可靠消息就是使用独立的消息服务,使用“预发送机制”把消息提早入库,业务肯定执行完毕,再修改消息状态为可发送,而后再发送消息给MQ,消费者再消费。
预发送机制
若是先执行业务,再发消息(先发消息再执行业务也不行),入kafka,可能马上就消费了。本地事务回滚是没法回滚已发送到kafka的消息的。使用预发送机制,保证了消息服务DB中有一条“初始化”状态的消息记录。业务异常,就不会“确认发送Msg”,消息就不会发送。
可靠场景下,甚至能够在消息服务中轮询”初始化“状态的且过了“一个时间段”(通常超过这个时间,确定是出问题了)的消息,再去查询业务系统是否完成,若是完成则自修复成"待发送"状态。
注:上图主业务做为生产者,严格来讲,消息服务平台才是生产者(若是把kafka做为中心的话)。
整个流程如上图:
本地消息表(业务系统+消息表,强一致性)
若是不使用独立的消息服务平台,在业务系统内部新建一张消息表,就能够彻底由一个本地事务来控制,这样第一、2步的“消息入库”、“确认发送”能够确保成功,也就不须要“轮询自修复”了,若是公司不要求使用统一消息服务平台的话,使用本地消息表也是ok的。
TCC 其实就是采用的补偿机制,其核心思想是:针对每一个操做,都要注册一个与其对应的确认和补偿(撤销)操做。TCC 实质上是应用层的2PC(2 PhaseCommit, 两阶段提交),比如把 XA 两阶段提交那种在数据资源层作的事务管理工做提到了数据应用层。TCC流程以下图:
如上图所示,步骤:
主业务活动请求(try)各个从业务服务预留资源。try过程的本地事务,是保证资源预留的业务逻辑的正确性。
若是在第一阶段全部业务资源都预留成功,那么confirm各个从业务服务,不然取消(cancel)全部从业务服务的资源预留请求。
优势:
相比XA是资源层面的分布式事务,强一致性,在两阶段提交的整个过程当中,一直会持有资源的锁。
TCC是业务层面的分布式事务,最终一致性,不会一直持有资源的锁。confirm/cancel执行的本地事务逻辑确认/取消预留资源,confirm和cancel就是补偿型事务
(Compensation-Based Transactions)。注意:confirm和cancel都是独立的本地事务,是对try的补偿。
缺点:
针对一个请求,须要从业务服务提供3个接口,供主业务服务调用,业务方改形成本高。
====参考=======
分布式事务 :第一节不少都是参考本文,写的不错。