7. 对比两阶段提交,三阶段协议有哪些改进?
在分布式系统中,各个节点之间在物理上相互独立,通过网络进行沟通和协调
在关系型数据库中,由于存在事务机制,可以保证每个独立节点上的数据操作都满足 ACID
两阶段和三阶段提交的具体流程是怎样的?三阶段提交又是如何改进的呢?
协调者统一调度
在分布式事务的定义中,如果想让分布式部署的多台机器中的数据保存一致性
就要保证在所有节点的数据写操作,要么全部都执行,要么全部都不执行
但是,一台机器在执行本地事务的时候无法知道其他机器中本地事务的执行结果
节点并不知道本次事务到底应该 Commit 还是 Rollback
两阶段和三阶段提交协议都是引入了一个协调者的组件来统一调度所有分布式节点的执行
让当前节点知道其他节点的任务执行状态,通过通知和表决的方式
决定执行 Commit 还是 Rollback 操作
两阶段提交协议
两阶段提交算法的成立是基于以下假设的:
- 在该分布式系统中,存在一个节点作为协调者(Coordinator)
其他节点作为参与者(Participants),且节点之间可以进行网络通信 - 所有节点都采用预写式日志,日志被写入后被保存在可靠的存储设备上
即使节点损坏也不会导致日志数据的丢失 -
所有节点不会永久性损坏,即使损坏后仍然可以恢复
20230729160956.jpg
提交请求节阶段
协调者将通知事务参与者准备提价事务,然后进入表决过程
在表决过程中,参与者将告知协调者自己的决策
同意(事务参与者本地事务执行成功)或取消(本地事务执行故障)
在第一阶段,参与节点并没有进行 Commit 操作
提交阶段
在提交阶段,协调者将基于第一个阶段的投票结果进行决策:提交或取消这个事务
这个结果的处理,必须当且仅当所有的参与者同意提交
协调者才会通知各个参与者提交事务,否则协调者将会通知各个参与者取消事务
参与者在接收到协调者发来的消息后将执行对应的操作
也就是本地 Commit 或者 Rollback
两阶段提交存在的问题
20230729161720.jpg三阶段提交协议
20230729161837.jpgCanCommit 阶段
协调者向参与者发送 Commit 请求,参与者如果可以提交就返回 Yes 响应,否则返回 No 响应
PreCommit 阶段
A. 假如协调者从所有的参与者获得的反馈都是 Yes 响应
那么就会进行事务的预执行:
- 发送预提交请求,协调者向参与者发送 PreCommit 请求,并进入 Prepared 阶段
- 事务预提交,参与者接收到 PreCommit 请求后,会执行事务操作
- 响应反馈,如果参与者成功执行了事务操作,则返回 ACK 响应,同时开始等待最终指令
B. 假如有任何一个参与者向协调者 发送了 No 响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就中断事务:
- 发送中断请求,协调者向所有参与者发送 abort 请求
- 中断事务,参与者收到来自协调者的 abort 请求之后,执行事务的中断
DoCommit 阶段
A. 执行提交
- 发送提交请求
协调者接收到参与者发送的 ACK 响应后
它将从预提交状态进入到提交状态,并向所有参与发生 DoCommit 请求 - 事务提交
参与者接收到 DoCommit 请求之后,执行正式的事务提交,并在完成事务提交之后释放所有事务资源 - 响应反馈
事务提交完之后,向协调者发送 ACK 响应 - 完成事务
协调者接收到所有参与者的 ACK 响应之后,完成事务
B. 中断事务
协调者没有接收到参与者发送的 ACK 响应
可能是因为接受者发送的不是 ACK 响应,也有可能响应超时,那么就会执行中断事务
####### C. 超时提交
参与者如果没有收到协调者的通知,超市之后会执行 Commit 操作
三阶段提交做了哪些改进
引入超时机制
在 2PC 中,只有协调者拥有超时机制,如果在一定时间内没有收到参与者的消息则默认失败
3PC 同时在协调者和参与者中都引入超时机制
添加预提阶段
在 2PC 的准备阶段和提交阶段之间,插入一个预提交阶段
是 3PC 拥有 CanCommit ,PreCommit,DoCommit 三个阶段
PreCommit 是一个缓冲,保证了在最后提交阶段之前各个参与节点的状态都是一致的
三阶段提交协议存在的问题
在阶段三中,如果参与者接收到了 PreCommit 消息后,出现了不能与协调者正常通信的问题
在这种情况下,参与者依然会进行事务的提交,这就出现了数据的不一致性
两阶段和三阶段提交的应用
两阶段提交是一种比较精简的一致性算法 / 协议
很多关系型数据库都是采用两阶段提交协议来完成分布式事务处理的
典型的比如 MySQL 的 XA 规范
MySQL Cluster 内部数据的同步就是用的 2PC 协议
MySQL 的主从复制
在 MySQL 中
- 二进制日志是 server 层,主要用来做主从复制和即时恢复使用的
- 事务日志(Redo Log)是 InnoDB 存储引擎层,用来保证事务安全的
在数据库运行中,需要保证 Binlog 和 Redo Log 的一致性
如果顺序不一致,则意味着 Master-Slave 可能不一致
开启 Binlog 后,如何保证 Binlog 和 InnoDB redo 日志的一致性呢?
MySQL 使用的是二阶段提交
内部会自动将普通事务当做一个 XA 事务(内部分布式事务)来处理:
- Commit 会被自动分成 Prepare 和 Commit 两个阶段
- Binlog 会被当做事务协调者(Transaction Coordinator), Binlog Event 会被当做协调者日志
总结
两阶段和三阶段提交协议是众多分布式算法的基础
- 介绍了两阶段提交和三阶段提交的具体流程
- 介绍了两种协议的区别
- 介绍了两阶段提交在 MySQL 主从复制中的应用