概述
目录
一、为什么浩瀚的互联网中又多了这么一段垃圾文本
二、正文开始
三、2PC
一. Prepare phase
二. Commit phase
四、3PC
一. CanCommit
二. PreCommit
三. doCommit
五、优缺点
一. 2PC的优点
二. 2PC的缺点
三. 3PC的优点
四. 3PC的缺点
一、为什么浩瀚的互联网中又多了这么一段垃圾文本
在看书或文档时,不知你是否和我一样,“满书都是熟悉的字眼,连起来念也知道在讲什么,但,‘满眼熟悉的汉字和词语反而让我分不清楚哪些是动词,哪些是名词,哪些是专用词语,哪些是描述过程的词语’”,这使我难以理解“这到底在讲什么”。对我来说,将专用词语专门分出来,整理成条理的条目,才是理解和记忆最好的方式
下面内容来自于“从Paxos到Zookeeper分布式一致性原理和实践”,完全是照抄书本,没啥新意,所以,当你看到这篇文章时,你可以去看书,或者也可以看这些整理过的内容
二、正文开始
2PC和3PC都是为了处理分布式事务的。阿里开源了一个Seata框架,用来处理分布式事务,在Seata框架中,分布式事务有三种角色
1.事务管理者(Transaction Manager)
2.事务协调者(Transaction Coordinator)
3.资源管理者(Resource Manager)
而,“从Paxos到Zookeeper分布式一致性原理和实践”中描述2PC和3PC时,使用的是
1. 协调者(Coordinator)
2. 参与者(Participant)
但,我不想用上面这两词,我采用Seata中的叫法,且,不使用“资源管理者(Resource Manager)”。下文主要有这几个词
1. 协调者(Coordinator),简称TC
2. 参与者(Participant),其实就是Seata中的事务管理者(Transaction Manager),本文中简称TM
3. 当前要执行的事务(Transaction),简称T
4. 整个分布式事务,称为是global transaction
5. 每个TM要执行的事务,称为是local transaction
三、2PC
2PC是将分布式事务分为两个阶段来处理:Prepare phase 和 Commit phase
一. Prepare phase
1. TC---->每个TM 发送 包含具体事务内容的 消息<Prepare, T>
2. 每个TM收到 消息<Prepare, T>,然后
a.该TM获取执行 自己local transaction 所需要的lock
b.该TM写 自己local transaction 的 undo&redo log
undo是记录修改前的数据,用于数据库回滚;redo是记录修改后的数据,用于提交事务后写入数据文件
c. 该TM真正执行 自己local transaction,但,并不提交(注意:并不提交 自己local transaction)
3. 每个TM---->TC 反馈执行事务的结果,“Prepare_Success”或“Prepare_Failed”
二. Commit phase
Commit phase取决于 TC收到的TM的反馈,执行 分支一 或者 分支二
分支一:TC收到 所有TM的反馈,且,全部为“Prepare_Success”,则
1. TC---->每个TM 发送 消息<Commit, T>
2. 每个TM收到 消息<Commit, T>,然后,
a. 该TM就 commit该TM自己local transaction
b. 该TM就 释放掉 自己local transaction 所占用的lock
3. 每个TM---->TC反馈“Commit_Success”
4. TC收到 所有TM的反馈,完成global transaction
我的疑问:
问题1:某个TM 进行commit时,难道不会“Commit_Failed”?
问题2:TC收到的所有TM反馈,如果包含“Commit_Failed”咋办?
2PC不就2个阶段嘛,所以没有后面阶段了呗。那么,此时TC还能咋办,想abort也abort不了啊?难道烂摊子就是:数据不一致,有些TM是“Commit_Success”,有些TM是“Commit_Failed”。不过,TC此时怎么定义“global transaction的结果”
问题3:如何定义“global transaction已完成”?
1. “TC向所有TM 发送 消息<Commit, T> 一结束”,就表明global transaction已完成。或
2. “只有当 TC收到 所有TM的反馈 后” 才表明 global transaction已完成
3. 难道TC还能 “commit/rollback global transaction”
4. “完成global transaction”还需要TC来宣布的(不可能吧,只有2个阶段啊,TC没机会宣布的啊)
问题4:假设,无论何种原因,TC 不能够 收到 全部TM的“Commit_Success”,此时,TC怎么定义“global transaction的结果”?此时,实际情况可能是,TC已经发送过 消息<Commit, T>,且
1. 可能全部TM都已commit成功,但某个TM断网不能反馈“Commit_Success”
2. 可能部分TM已commit成功,但,部分TM未commit或commit失败,所以反馈了“Commit_Failed”
TC此时咋办,我觉得没招啊?
问题5:某个TM 何时 释放掉 自己local transaction 所占用的lock?
1. 每个TM commit完自己的local transaction后,立即释放 自己local transaction的lock
2. 要等待TC宣布 “TC:我宣布,所有TM都已经commit完成了,每一个TM请各自释放掉 自己local transaction 所占用的lock吧”,然后,每个TM才释放lock
分支二:如果 TC 收到 任何一个TM的反馈为“Prepare_Failed”(超时未反馈等同于“Prepare_Failed”),则
1. TC---->每个TM 发送 消息<Abort, T>
2. 每个TM收到 消息<Abort, T>,然后,
a. 该TM就 abort该TM自己local transaction
b. 该TM就 释放掉 自己local transaction 所占用的lock
3. 每个TM---->TC反馈 “Abort_Success”
4. TC收到 所有TM的反馈,完成global transaction
我的疑问
很滑稽的一个问题,某个TM 进行abort时,难道不会“Abort_Failed”?
“commit时的全部问题”在abort时 都存在一份类似的问题
四、3PC
把 2PC的Commit phase,拆分为 PreCommit phase 和 doCommit phase 两个阶段,就得到3PC
3PC即: CanCommit phase,PreCommit phase 和 doCommit phase
一. CanCommit
1. TC---->每个TM 发送 消息<CanCommit, T>
2. 每个TM收到 消息<CanCommit, T>,然后,
该TM就 检查 自己local transaction 能否执行。注意,仅仅是检查是否可以执行,并不获取任何锁,不占据任何资源
3. 每个TM---->TC 反馈“CanCommit_Success”或“CanCommit_Failed”
二. PreCommit
分支一:上步得到的全部都是 “CanCommit_Success”
1. TC---->每个TM 发送 消息<PreCommit, T>
2. 每个TM收到 消息<PreCommit, T>,然后,
a.该TM获取执行 自己local transaction 所需要的lock
b.该TM写 自己local transaction 的 undo&redo log
undo是记录修改前的数据,用于数据库回滚;redo是记录修改后的数据,用于提交事务后写入数据文件
c. 该TM真正执行 自己local transaction,但,并不提交(注意:并不提交 自己local transaction)
3. 每个TM---->TC 反馈执行事务的结果,“PreCommit_Success”或“PreCommit_Failed”
分支二:上步得到至少包含一个 “CanCommit_Failed”
1. TC---->每个TM 发送 消息<Abort, T>
2. 每个TM收到 消息<Abort, T>,然后,
无需abort 自己local transaction 所占用的lock,因为CanCommit时 仅仅检查,并不 获取lock(和2PC不同喽)
3. 每个TM---->TC反馈 “Abort_Success”
三. doCommit
分支一:上步得到的全部都是 “PreCommit_Success”
1. TC---->每个TM 发送 消息<doCommit, T>
2. 每个TM收到 消息<doCommit, T>,然后,
a. 该TM就 commit该TM自己local transaction
b. 该TM就 释放掉 自己local transaction 所占用的lock
3. 每个TM---->TC反馈“doCommit_Success”
4. TC收到 所有TM的反馈,完成global transaction
我的疑问
“2PC时 commit时的全部问题”在 3PC的doCommit phase 都存在一份类似的问题
分支二:上步得到至少包含一个 “PreCommit_Failed”
1. TC---->每个TM 发送 消息<Abort, T>
2. 每个TM收到 消息<Abort, T>,然后,
a. 该TM就 abort该TM自己local transaction
b. 该TM就 释放掉 自己local transaction 所占用的lock
3. 每个TM---->TC反馈 “Abort_Success”
4. TC收到 所有TM的反馈,完成global transaction
我的疑问
“2PC时 abort时的全部问题”在 3PC的doCommit phase 都存在一份类似的问题
五、优缺点
一. 2PC的优点
原理简单,实现方便
二. 2PC的缺点
1. 同步阻塞
Commit phase 所有TM都已获取到 自己local transaction所需的lock,所有TM都处于阻塞状态,必须等待“最慢TM 释放掉锁之后”,global transaction才能完成,所有TM的同步阻塞才结束
2. 单点问题
TC在2PC中非常重要,假设Prepare phase刚刚结束,TC挂了,于是,无法进入Commit phase,所有TM都处于 “获取到各自local transaction的lock,但,又无法完成事务”的状态。当然,这是单点问题,这同样也是“所有TM的同步阻塞无法结束”的问题
3. 数据不一致
进入Commit phase时,TC给部分TM发送了 消息<Commit, T>,另外一部分TM 尚未发送 消息<Commit, T>,TC挂了。(或,这种是我自己想的,没有看到书本上有讲,某个TM“Commit_Failed”)。于是,分布式系统便出现了 数据不一致 现象
这就是我上面“臆想”出的疑问:无论何种原因,TC 不能收到 全部的“Commit_Success”,那么,TC此时怎么定义“global transaction的结果
4. 太过保守
Prepare phase时,TC 询问 每个TM “对于事务T,大家都可以提交吗”的时候。如果某个TM出现故障无法响应,TC就只能依靠超时 来判断是否中断事务,最终事务失败。这暴露了什么问题呢?这暴露了,2PC太保守,任何一个节点失败,global transaction就失败。当然,你还得意识到:此时,其他TM 都各自 获得了自己local transaction的lock,所以,导致了上面的“所有TM 同步阻塞”
三. 3PC的优点
1. 降低了TM的阻塞范围
当然,是“降低了”,不是“消除了”。因为,基本上3PC的CanCommit phase 回复“CanCommit_Success”时,绝大部分情况下都是 确实可以执行事务的
2. 单点故障后,能够继续达成一致
没搞懂这里在说什么
四. 3PC的缺点
TM收到<PreCommit, T>后,如果网络分区,假设 TM-1可以与TC通信,TM-2不可以
1. TM-1 回复 “PreCommit_Failed”,且,TC收到了
2. TM-2 回复 “PreCommit_Success”,当然,由于网络分区了,TC收不到。
注意:TM-2等待TC的<Commit, T>,但,等不到了,超时之后,TM-2会 自信的提交事务
但,TC真正发过来的是<Abort, T>,当然,TM-2是收不到的
最终,TM-1回滚事务,TM-2提交了事务
最终结论是:在网络分区时,3PC依然存在数据不一致问题
Enjoy
最后
以上就是冷静花瓣为你收集整理的2PC和3PC一、为什么浩瀚的互联网中又多了这么一段垃圾文本二、正文开始三、2PC四、3PC五、优缺点的全部内容,希望文章能够帮你解决2PC和3PC一、为什么浩瀚的互联网中又多了这么一段垃圾文本二、正文开始三、2PC四、3PC五、优缺点所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复