分布式事物-XA协议
什么是XA
我们常见的数据库连接事务中的 XA 是指由 X/Open 组织提出的分布式事务处理的规范. XA 规范主要定义了事务管理器(Transaction Manager)和局部资源管理器(Local Resource Manager)之间的接口.需要数据库厂商对此协议的实现才支持 我们常用的oracle和mysql 高版本都对其进行了实现,在我们出现分库分表时或者一个请求涉及到多个服务节点,则面临一个事物操作多个表多个库。
基于XA协议实现的分布式事务对业务侵入很小。 它最大的优势就是对使用方透明,用户可以像使用本地事务一样使用基于XA协议的分布式事务。 XA协议能够严格保障事务 ACID
特性。
严格保障事务 ACID
特性是一把双刃剑。 事务执行在过程中需要将所需资源全部锁定,它更加适用于执行时间确定的短事务。 对于长事务来说,整个事务进行期间对数据的独占,将导致对热点数据依赖的业务系统并发性能衰退明显。 因此,在高并发的性能至上场景中,基于XA协议的分布式事务并不是最佳选择。
2PC
2PC协议也成为2段提交,1prepare阶段,2commit阶段。
所谓的两个阶段是指:第一阶段:准备阶段(投票阶段)和第二阶段:提交阶段(执行阶段)。
准备阶段
事物协调者向所有事物参与者发送prepareq消息,每个参与者要么直接返回失败(如权限验证失败.命令格式错误),要么在本地执行事务,写本地的redo和undo日志,但不提交。
准备阶段的三个步骤
1.协调者节点向所有参与者节点询问是否可以执行提交操作,并开始等待各参与者节点的响应。 2.参与者节点执行询问发起为止的所有事务操作,并将Undo信息和Redo信息写入日志。(注意:若成功这里其实每个参与者已经执行了事务操作) 3.各参与者节点响应协调者节点发起的询问。如果参与者节点的事务操作实际执行成功,则它返回一个”同意”消息;如果参与者节点的事务操作实际执行失败,则它返回一个”中止”消息。
提交阶段
如果协调者收到参与者的失败消息或者超时消息则通知所有参与者回滚(rollback),否则通知所有参与者提交(commit),参与者根据协调者的提交或者回滚消息执行提交或回滚,并释放所有锁定资源
2PC的缺点
如果虽然2PC看起来可以满足一致性,但是有以下缺点
1.在提交阶段,如果协调者发生故障,则参与者会一直阻塞挂起(可以通过重新选举新的协调者解决,但是并不能解决,协调者因为发送故障导致的阻塞问题)
2.在提交阶段,如果部分参与者收到提交消息,部分参与者因为发生故障未收到commit消息,这个时候就出现数据不一致
3.性能问题:所有参与者在事务提交阶段处于同步阻塞状态,占用系统资源,容易导致性能瓶颈。
3PC
由于二阶段提交存在着诸如同步阻塞、单点问题,数据不一致问题,所以,研究者们在二阶段提交的基础上做了改进,提出了三阶段提交。
3PC和2PC不同的是
1.参与者和协调者都引入了超时机制
2.在一阶段和二阶段之间增加了一个准备阶段,保证在提交阶段各个事物参与者的状态是一致的
也就是说,除了引入超时机制之外,3PC把2PC的准备阶段再次一分为二,这样三阶段提交就有CanCommit
、PreCommit
、DoCommit
三个阶段。
CanCommit阶段
1.事务询问 协调者向参与者发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应。
2.响应反馈 参与者接到CanCommit请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态。否则反馈No
PreCommit阶段
协调者根据参与者的canCommit反应情况来决定是否可以继续事务的PreCommit操作。根据响应情况,有以下两种可能。
1.假如协调者从所有的参与者获得的反馈都是Yes响应,那么就会执行事务的预执行。
1.发送预提交请求 协调者向参与者发送PreCommit请求,并进入Prepared阶段。
2.事务预提交 参与者接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中。
3.响应反馈 如果参与者成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令。
2.假如有任何一个参与者向协调者发送了No响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。
1.发送中断请求 协调者向所有参与者发送abort请求。
2.中断事务 参与者收到来自协调者的abort请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断。
doCommit阶段
该阶段进行真正的事务提交,也可以分为以下两种情况。
1.在preCommit阶段所有事物参与者都返回YES
1.发送提交请求 协调接收到参与者发送的ACK响应,那么他将从预提交状态进入到提交状态。并向所有参与者发送doCommit请求。 2.事务提交 参与者接收到doCommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源。 3.响应反馈 事务提交完之后,向协调者发送Ack响应。 4.完成事务 协调者接收到所有参与者的ack响应之后,完成事务。
1.中断事务 协调者没有接收到参与者发送的ACK响应(可能是接受者发送的不是ACK响应,也可能响应超时),那么就会执行中断事务。
在doCommit阶段,如果参与者无法及时接收到来自协调者的doCommit或者rebort请求时,会在等待超时之后,会继续进行事务的提交
为什么参与者超时会执行事物提交,可能是因为到这个阶段大概率是提交 所以执行提交
通过这里可以看出3阶段并没有解决数据不一致的问题,比如协调者向参与者发送rollback命令,但是参与者因为某些原因没有收到 执行了commit
mysql对XA的使用
数据厂商都是基于2p'c
#查看mysql是否支持XA SHOW VARIABLES LIKE '%XA%' #开启XA模式 xa比传统事物慢10倍以上 SET innodb_support_xa = ON #---------------------第一阶段start----------------- #开启xa事务wsh 我们定义的id 第一阶段准备阶段 xa start ‘xa_000001’; #执行insert语句 insert into name(id,name) values(1,‘wsh’); #这里必须是end 事物提交 固定的操作方式 xa end ‘xa_000001’; #提交会有返回值 决定后面的commit和rollback操作 xa prepare ‘xa_000001’; #---------------------第一阶段end----------------- #---------------------第二阶段start---------------- #提交xa事务 xa commit ‘xa_000001’; #---------------------第二阶段end----------------
java JTA
Java 通过定义 JTA 接口实现了 XA 模型,JTA 接口中的 ResourceManager
需要数据库厂商提供 XA 驱动实现, TransactionManager
则需要事务管理器的厂商实现,传统的事务管理器需要同应用服务器绑定