XA规范
分布式系统架构下,进行事务提交,保持一致性而设计的一种算法。各个系统进行事务提交的时候,都能知道成功与否,都能实现回滚或是成功提交。但是分布式框架下,多系统进行事务提交,各个系统无法感知其他系统中的事务是否正常提交了或是需要回滚。这个时候需要引入一个事务协调者去协调各个节点完成事务操作。有了分布式事务的场景,就会有解决该问题的方式规范,XA规范就是解决分布式事务的规范。分布式事务的实现方式有很多种,最具有代表性的是XA分布式事务协议。XA协议包括两阶段提交(2PC)和三阶段提交(3PC)两种实现。思路:参与者将操作成本通知协调者,再由协调者根据所有参与者的反馈情况决定各个参与者是否需要提交操作还是终止操作
2PC 两阶段提交
第一阶段: 准备阶段,预提交
第二阶段:提交/回滚阶段
准备阶段
事务协调者给每个参与者发送prepare消息,参与者直接返回失败 ,或是在本地执行事务,写本地的redo log 和undo log,但是不提交,返回同意给协调者
提交/回滚阶段
事务协调者收到所有参与者返回的消息,根据消息决策出进行提交或是回滚,在发送信息给所有参与者
如果遇到参与者失败或是超时,直接发送rollback.消息 否则发送commit消息。
2PC 存在的缺点
- 同步阻塞,参与者在第一阶段完成本地事务(未提交)返回同意,在等待协调者收集全部参与者的回复并发送一下一步指令的这段时间是阻塞的,占用参与者CPU 和数据库连接资源。
- 单点故障 由于协调者的重要性,当协调者出现故障的时候,参与者会一直阻塞下去。 尤其是第二阶段,所有参与者锁定了事务资源,无法完成事务操作。
- 数据不一致 在二阶段提交阶段二中,如果协调向参与者发送commit请求之后,发送局部网络异常或是在发送commit的过程中协调者挂了,导致部分参与者收到commit 请求去完成事务,有部分参与者没收到,会出现数据一致性问题
- 两阶段提交无法解决的问题; 协调者发出commit消息后挂了,而唯一接收到这个消息的参与者也同时挂了,那么即使调用者通过协调选举产生新的调用者,这个事务的状态也是不确定的,没人知道事务是否被提交了。
处理方法,补偿,手动补偿或是脚本补偿
3PC 三阶段提交
CanCommit 阶段
协调者向参与者发送cancommit请求,询问是否可以执行事务提交操作,然后等待参与者返回。参与者接收到请求后,如果认为可以提交就返回Yes, 不可以就返回No
PreCommit阶段
- 假如协调者从所有的参与者获得反馈都是Yes响应,那么久会执行事务预执行
- 向所有参与者发送预提交请求,进入prepared 阶段
- 参与者接收到Precommit 请求后,会执行事务操作,更新undo log 和redo log ,不提交
- 如果参与者成功执行事务,则返回ACK 响应,等待最终指令
- 假如第一阶段任何参与者向协调者发送No响应或是超时等待之后,协调者没有接收到参与者的响应,那么执行事务中断。
- 协调者向所有参与者发送abort 请求
- 参与接收到abort请求后,执行事务中断
c. 参与者如果没收到precommit请求会进行中断操作
Docommit 阶段
执行提交
- 协调者收到ACK 响应,那么他将从预提交状态进入提交状态,并向所有参与者发送docommit请求
- 参与者收到docommit 请求后,执行正式的事务提交,并完成事务资源释放。
- 事务完毕,参与者向协调者发送ACK响应
- 协调者收到所有参与者的ack 完成事务
- 如果参与者没收到docommit 会自动提交
中断事务
对于第二阶段参与者的ACK 响应,如果协调者没收到或是超时或是不是ACK响应,那么就会执行中断事务
- 协调者发送abort 请求
- 参与者接收到abort请求,进行回滚,释放事务资源
- 回滚完毕,参与者向协调者发送ACK响应
- 协调者收到所有参与者的ack 完成事务
2PC 和 3PC 区别
- 3PC 比2PC 多了一个can commit 阶段,减少不必要的资源浪费,因为2PC 第一阶段就占用了数据库资源,3PC 是第二阶段才会,第一阶段只是进行SQL 校验,如果不能执行就直接返回,减少资源占用
- 引入了超时机制,同时在参与者和协调者都引入了超时机制
2PC 只有协调者有超时机制,超时后,发送回滚指令给参与者
3PC 协调者参与者都有超时机制
协调者遇到参与者超时:canCommit,preCommit收不到参与者的应答,会向所有参与者发送中断指令
参与者遇协调者到超时: precommit阶段,参与者进行中断: docommit,参与者进行提交