关于再3B中出现测试一直运行情况的分析

3B中,我们组遇到过测试一直进行不失败的情况。首先说明发生这一问题的测试,我们所有的该类问题都发生在ConfChange下,因此如果在无ConfChange的测试中出现这一问题,可能与本文描述的情况无关,先说场景:

  1. 存在Unrealiable;
  2. remove直到最后两个节点;

此时会有如下可能发生:

  • NodeA为此时的Leader节点,当该节点收到了removeNodemsg,他会hug这个消息来进行共识,NodeB收到了共识消息并且对节点A发出了回应,根据commit的更新规则,这个NodeB的commit并不会更新,而是要等到NodeA更新commit后,NodeB才会根据NodeA的AppendEntries更新其commit,但是这里存在一个巨大的问题,如果说之后的AppendEntries被drop掉了,而NodeA有执行了一个handleRaftReady ,那在NodeB的视角中,NodeA并没有被remove,但是NodeA也用来不会和NodeB进行通信了,NodeB就会陷入不断timeout,但是因为他永远无法达成共识,所以就会无限循环下去了;

解决方案:正常而言会想到的一个解决方案必然是先发送一个Transferee的消息,使NodeB变成Leader,然后再执行remove,但是我们思考后发现,这样也无法处理这个问题。
因为在这里, Transferee是不需要进行同步的,Transferee的逻辑是,NodeA如果发现这个NodeB的Match没有跟上自己,就会把自己的日志全部发送给她,然后NodeA回应以后再发送一个timeout信号,让NodeB进行选举。这里在NodeB回应以后,NodeA会觉得自己的所有日志都已经共识了,因此NodeA的commit会更新,但是NodeB已经timeout了,所以他会上任以后自己进行commit更新,然后之前的情况就发生了,他永远无法成功成为Leader,因为A已经不存在了。
解决方案:我们组目前给出的解决思路是节点数小于等于三个的时候,对于存在remoce的消息连续发送5次,用来对冲unreliable,更好的解决方案目前没有想到,大家可以一起思考一下。

4 个赞

我的解决方案是在remove node中判断删除节点后剩下自己时become leader,逻辑比较简单
因为在我的实现中update commit是在收到response时执行的,随后立即发送commit后的空包给peers,所以可以保证只有两个节点时删除自身的操作在发送消息后才执行(要保证destroy() 晚于 send() 函数)
这里有个坑就是通过add node生成的节点的prs中好像不会有自己,这部份内容还没深究,还不太清楚是哪里出了问题

我说的这种情况,Node的remove node消息都没办法commit啊,那这个消息时不会执行的,你这样也是不能保证的,commit更新后立刻发送心跳时2A验证过的,我们还对这个做了一些优化,但是这个空包在unrealiable的情况下也是可能drop掉的

会在消息发送后执行,但是发送出去的消息可能因为网络因素无法到达,没有手段保证删除操作在对方确认commit更新后执行。

了解了,这种情况和网络被分割很像(如果一个follower被隔离了那么它无法变成leader)
我感觉发多次无法从根本上解决问题,可能需要加入类似timeout的属性对没人回应的次数进行判断才可能解决

是的,多次没办法从根本解决问题,我们也没有想到好的解决办法。这个要根本解决我感觉要从PD端入手。

如果delete的是leader 拒绝掉这个proposal 先tranferleader 在新的leader上处理这个。这个最起码保证集群正常运行 ,但是会有节点 失联

我就是这样处理的,能降低出问题的几率,但不是绝对安全

比如:
peer1(leader)proposal删除peer2,但是在commit之前peer2成为了leader,结果还是leader删除自己。