汤瑞麟_摸鱼瞎搞二人组
(Reilly.Tang-摸鱼瞎搞二人组)
1
3B中,我们组遇到过测试一直进行不失败的情况。首先说明发生这一问题的测试,我们所有的该类问题都发生在ConfChange
下,因此如果在无ConfChange
的测试中出现这一问题,可能与本文描述的情况无关,先说场景:
- 存在Unrealiable;
- remove直到最后两个节点;
此时会有如下可能发生:
- NodeA为此时的Leader节点,当该节点收到了
removeNode
的msg
,他会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中好像不会有自己,这部份内容还没深究,还不太清楚是哪里出了问题
汤瑞麟_摸鱼瞎搞二人组
(Reilly.Tang-摸鱼瞎搞二人组)
3
我说的这种情况,Node的remove node消息都没办法commit啊,那这个消息时不会执行的,你这样也是不能保证的,commit更新后立刻发送心跳时2A验证过的,我们还对这个做了一些优化,但是这个空包在unrealiable的情况下也是可能drop掉的
汤瑞麟_摸鱼瞎搞二人组
(Reilly.Tang-摸鱼瞎搞二人组)
4
会在消息发送后执行,但是发送出去的消息可能因为网络因素无法到达,没有手段保证删除操作在对方确认commit更新后执行。
了解了,这种情况和网络被分割很像(如果一个follower被隔离了那么它无法变成leader)
我感觉发多次无法从根本上解决问题,可能需要加入类似timeout的属性对没人回应的次数进行判断才可能解决
汤瑞麟_摸鱼瞎搞二人组
(Reilly.Tang-摸鱼瞎搞二人组)
6
是的,多次没办法从根本解决问题,我们也没有想到好的解决办法。这个要根本解决我感觉要从PD端入手。
charstal
(胡煜@名字好难取战队)
7
如果delete的是leader 拒绝掉这个proposal 先tranferleader 在新的leader上处理这个。这个最起码保证集群正常运行 ,但是会有节点 失联
我就是这样处理的,能降低出问题的几率,但不是绝对安全
比如:
peer1(leader)proposal删除peer2,但是在commit之前peer2成为了leader,结果还是leader删除自己。