2/3阶段提交解决的问题是分布式数据操作一致性问题,即在不同节点间数据多个操作的原子性问题,比如在A节点的数据增加和B节点数据的减少需要原子操作。
解决方案:在各个分布式节点之上引入TC(Trancaction Coordinator),由TC进行最终commit操作协调,只有各个节点的预操作(precommit)都成功才进行提交,否则rollback。
两阶段提交,第一阶段precommit,向各个分布式节点发送确认信息,各个节点将会执行操作(但是不提交),同时写入redo日志和undo日志,完事后通知TC准备完毕;
第二阶段,TC接收到所有的节点ACK回复之后将会下发commit指令,如果有节点没有响应或者相应为准备失败,将会下发abort指令;各个节点接收到了commit指令之后,将会提交数据;如果接收到的是abort指令,将会通过执行undo指令进行回滚;
这里注意,如果在第二阶段commit失败了,比如机器宕机之类,将会在机器重启之后继续提交;总之第一阶段回复ACK就代表着该节点有能力提交成功。如果是commit失败了,那么就需要手动回复,就像大神讲述的:
no distributed asynchronous protocol can correctly agree in presence of crash-failures
所以2阶段并不能解决commit因为宕机等原因导致失败的场景;除此之外,2阶段提交还是有软肋,就是TC如果挂了怎么办,所有的节点还都在这里等着TC下达最终指令,相关表的等资源都在锁定状态,为了避免这种情况发生,有人提出了3阶段提交,基本思想如下:
第一阶段can commit,一个TC比较泛泛的征询各个节点,其实本质是看节点是否在,或者说服务是否正常;节点一看自己正常回复ACK
第二阶段pre commit,TC一看大家都很正常将会下发precommit指令,各个节点接收到了precommit指令之后,将会执行操作,并写入redo日志和undo日志;当然,如果TC发现can commit阶段有节点有问题,这事就算了,也不需要通知各个节点,因为can commit阶段大家什么事情都没有做,引入can commit阶段一段程度上可以减轻一些失败场景的操作,比如有的节点本身已经当了,其他节点就不想要执行语句,写入redo/undo日志了。
第三阶段do commit,TC一看大家的precommit都已经ready了,就会下发commit指令;敲黑板,如果各个节点在指定时间内没有收到commit指令,将会自动commit,之所以选择commit而不是rollback,是因为经过了前面两个阶段,大概率大家都会提交成功(实现数据一致性),所以超时的操作就是提交;如果TC发现有的节点在precommit阶段报错,或者没有相应,将会下发abort指令,各个节点执行undo日志内容进行rollback。
所以三阶段和二阶段本质的差别在于commit阶段增加了超时提交机制,避免在TC自身出现故障,或者网络出现故障的时候导致资源不能及时释放的问题。
redo日志/undo日志
要理解redo/undo日志要明白数据操作机制,在传统的关系型数据库中,对于数据的事务操作:
1)通知数据库服务器锁定(表)资源;
2)客户端进行修改记录(比如可以通过Hedisql的等数据库client直接进行修改)
3)commit之后,client将会把修改信息提交到server段,server对数据处理完成记录到文件中(落盘)后释放资源;
对于很多大数据的数据库比如LSM tree
1)Client端提交的数据首先放置到内存中(易丢失)
2)条件满足了之后,将会将内存数据刷到硬盘中,实现落盘(靠谱)
无论是哪一种,我们看到,在没有落盘之前,都是有风险的,一旦客户端/内存发生故障,比如宕机之类将会导致数据丢失,为了实现数据丢失后仍然可以回复,于是设置了redo日志机制,所有的未落盘的数据都将会进行记录,每次服务重启都会首先读取redo日志,实现未落盘的数据重新加载,保证数据不丢失。
在分布式事务保证中,为了保证precommit阶段执行之后的数据(并未落盘)及时在意外服务重启后仍然能够恢复当时状态,所以将数据操作写入到了redo文件中。
至于undo文件,比较好理解,就是记录下来数据修改前的状态,一旦发生rollback,直接将内存值以及client端的数据回滚到之前的状态。
参考:
https://blog.csdn.net/lengxiao1993/article/details/88290514
https://my.oschina.net/wangzhenchao/blog/736909
https://www.hollischuang.com/archives/681
https://www.letiantian.me/2014-06-18-db-undo-redo-checkpoint/