2PC
2PC,也就是两段提交:
1)第一阶段参与值接收到开始事务的请求之后,返回accept或者abort,如果返回accept,就预先执行事务,并记录相关的日志和undo。
2)第二阶段coordinator发起commit,participant接受后返回commit或者abort。
3PC
3PC,是三段提交:
1)第一阶段接受到开始事务的请求之后,根据participant的情况,返回accpert或者abort。
2)第二阶段coordinator发起pre-commit请求,participant prepare to commit或者abort或者超时commit,commit即会执行事务,并记录相关的日志和undo。
3)第三阶段coordinator发起commit请求,participant commit或者abort或者超时commit。
从上面的提交阶段对比可以看出来,3PC与2PC相比,将2PC拆分成两个阶段,以及增加了超时结果。
这样的改进是为了解决什么问题呢?
先看一个例子:(从知乎上面看到,在这里按照印象进行转述,也可以到连接中查看原文:https://www.zhihu.com/question/36899436)
什么情况下,2PC阶段会出乱子?
--如果只有一个coordinator down了,重新选主就可以了。
--如果只有一个participant down了,集群相当于少了个节点,也没有问题。
--有coordinator及一个节点先后down了,新的coordinator,需要尝试去判断down的节点的状态。
1)假如当前有另外一个节点的日志记录第一阶段返回abort,那么down的节点无论第一阶段是accept或者abort,coordinator应该rollback事务,整个集群事务一致。
2)假如当前另外一个节点的日志记录第一阶段返回accept,那么down的节点可能是第一阶段accpet或者abort,或者第二阶段commit,都有可能,所以集群无法判断,这个时候只能够等待。
同样的场景,对于3PC:
1)假如当前有另外一个节点的日志记录第一阶段返回abort,那么down的节点无论第一阶段是accept或者abort,coordinator应该rollback事务,整个集群事务一致。
2)假如当前另外一个节点的日志记录第一阶段返回accept,down节点可能是第一阶段accpet或者abort或者第二阶段pre-commit阶段,这个时候rollback事务,整个集群事务依然一致。
3)假如另外一个节点的日志记录是处于pre-commit阶段,那么down节点第一阶段不可能为abort,那么无论是处于第一阶段accept或者pre-commit阶段或者commit阶段,都可以进行提交。
按照以上的情景,3PC解决了2PC出现的节点状态不可知的情况,加上超时策略继而避免了单点故障导致集群hung死的情况。
对于3PC,也有个无法解决的问题:由于网络原因,一个原本应该接受abort指令的coordinator由于超时commit而导致的集群不一致的情况。
(以上是理论基础,后续结合mysql innodb 日志提交的相关知识进行介绍)