xnnyygn / xraft

xnnyygn's raft implementation
MIT License
228 stars 107 forks source link

如果未提交的日志放在内存中,会不会导致已提交后也会被推翻? #18

Open yanwz opened 3 years ago

yanwz commented 3 years ago

假设有节点 1,2,3,4,5 1 是leader 客户端写入一条消息 leader成功同步给2,3 两个节点(此时未提交日志保存在内存中) leader 增加commitIndex 并提交日志(还未同步给2,3)

假设这个时候 节点1下线,节点2重启(内存中未提交的日志不存在了) 接下来的选举节点2成为leader(是可以的,因为4,5节点会支持) 这个时候会导致之前上一个term节点1已提交的日志被推翻.

xnnyygn commented 3 years ago

首先,日志是有持久化前提的。内存日志只是为了调试存在的。所以你的问题中节点2重启后日志是最新的,最终会同步给4和5,不存在日志冲突的问题。

yanwz commented 3 years ago

感谢回复。我最近在拜读您的《分布式一致性算法开发实战》 ,其中提到有三种日志模式,1:未提交日志 放在缓存 已提交日志持久化到文件并删除缓存 2:未提交日志直接写入文件 已提交 无操作 3:未提交日志 写入文件和缓存 已提交日志 删除缓存,我上面的问题就是说的第一种模式情况下产生的,因为未提交的日志是没有持久化的。

xnnyygn commented 3 years ago

第一种模式下,提交时日志是写到文件里去的,此时节点2重启时会从文件读取日志,不会产生日志丢失的情况。换句话说,日志提交成功 -> 写入文件成功,写入文件成功 -> 日志不会丢失。结果是节点2或者3成为leader,没有日志冲突。

yanwz commented 3 years ago

节点1(leader),2,3,4,5 1:leader收到客户端消息保存到内存(未提交),然后将日志同步给 follower节.2,3将日志保存到内存,当前日志还是未提交状态 2:leader收到2,3节点的确认,将内存中的日志保存至文件,更新commitIndex,此时这条日志在leader节点是已提交状态了; 3:leader 同步 commitIndex 到follwer节点,follower节点将日志保存至文件,删除内存里的日志,更新commitIndex 假设上面第二步执行完leader就down机了,节点2重启(内存中未提交的日志不存在了) ,接下来的选举节点2成为leader(是可以的,因为4,5节点会支持) 这个时候会导致上面第二步节点1已提交的日志被覆盖.

xnnyygn commented 3 years ago

首先我理解你这个场景是针对这个实现设计出来的场景,其次这种场景下节点3更有可能成为leader而不是节点2,节点2重启需要时间,重启之后也不是立马开始选举,相比之下,节点3发现没有心跳信息之后立马开始选举过程。

如果你问一部分日志放在内存中同步过程中丢失了怎么办,那你可以考虑 1:数据是否会丢失,可能性有多大 2:数据丢失会导致什么问题 3:有什么解决方案

按照你设计出来的场景,commtIndex没有同步到follower,follower的数据放在内存并且重启了,此时这个follower是否会成为leader然后覆盖掉其他节点的数据,首先要看leader是否仍旧存在,你的场景恰好leader宕机了,其次这个follower要抢在其他follower之前宣布自己想要成为leader并且成功升级。只能说三个条件加在一起机率极小。 那么数据丢失会造成什么问题,客户端传来的指令消失了,此时客户端会发生什么,原先的leader宕机了,所以客户端收不到回复或者超时了,客户端会认为指令没有成功。事实上客户端此时根本不能判断指令成功。 解决方案有解决和不解决两种。不解决是因为机率极小危害不大不予考虑,解决的话是重启前强制把内存数据写入文件(commitIndex启动时为0和文件无关)或者回归全部是文件的实现方式。前者你可能会说不能处理强制kill所以你的意思是文件才是安全的。

未提交的数据放在内存还是直接放在文件里和具体实现有关,只要这个实现不破坏算法本身的语义。你可以想象数据库,你开了一个事务,没有提交之前,数据库重启了,你认为未提交的数据可以继续被访问到,还是丢失了?个人认为不能预期数据库会保留未提交的数据(当然很多数据库因为MVCC会保存数据)。回过头来看Raft算法中,未提交的数据是否一定需要存在,算法本身没有给出明确的要求。假如给了,那些用批量日志保存和异步日志保存机制的产品级别Raft算法实现也是有问题的,他们都没有在回复leader时立即写入日志。

希望上面的回复能解决你的问题。