baidu / braft

An industrial-grade C++ implementation of RAFT consensus algorithm based on brpc, widely used inside Baidu to build highly-available distributed systems.
Apache License 2.0
3.99k stars 886 forks source link

节点会给不在组成员列表中的其他节点投票 #303

Open weingithub opened 3 years ago

weingithub commented 3 years ago

我看了下handle_pre_vote_request中的代码处理,没有判断server_id是否在当前的_conf成员列表中。因此,节点就有可能给一个 刚启动,还没有通过add_peer加到组里面的节点投票。不知道当时是基于什么考虑没有加这个限制呢??

PFZheng commented 3 years ago

每个peer看到的conf可能是不一样的,如果去检查server_id是否在当前的_conf成员列表,可能没法选出主。例如,一个 3 节点的复制组,发生过很多次配置变更,现在有效节点是 {7, 8, 9},9 刚加入,日志滞后很多,本地的 conf 还停留在很早的版本,如 {1, 2, 3},这时候 7、8 里挂掉一个,如果判断 server_id,就选不出主来了

PFZheng commented 3 years ago

你说的第二个问题不会发生,这里有个隐含的前提是,投票是依据自己看到的 conf,一个没加入的节点,是不会被大家看到的

weingithub commented 3 years ago

你说的第二个问题不会发生,这里有个隐含的前提是,投票是依据自己看到的 conf,一个没加入的节点,是不会被大家看到的

可能和我们的成员变更方式有关吧。我们是这么处理成员变更的,加入原来的组成员是1,2,3。现在准备用4替换3,因此我们会先 启动4,设置成员是1,2,4。然后向组的leader调用add_peer,这个时候,Leader的组成员就变成了1,2,3,4。然后我们再删除3。最终组的成员变为1,2,4.所以在4起来的时候,它会向1,2发送消息。如果2是落后的数据节点,这个时候,如果4学习到了比2更新的数据,那么2就会给4投票。那么4就会成为leader。同时,原来的1,2,4因为假定的2是落后的,因此1,4数据接近,又会互相投票成为leader,这个时候不是会有问题吗?

Edward-xk commented 3 years ago

因此我们会先启动4,设置成员是1,2,4

你们这种不经过 leader 直接指定 conf 的做法是比较危险的,容易出现脑裂的 case; 建议的做法是新节点起来都是空的配置,然后走配置变更的接口,可以是先加再减,也可以走 change_peers 一步到位

weingithub commented 3 years ago

因此我们会先启动4,设置成员是1,2,4

你们这种不经过 leader 直接指定 conf 的做法是比较危险的,容易出现脑裂的 case; 建议的做法是新节点起来都是空的配置,然后走配置变更的接口,可以是先加再减,也可以走 change_peers 一步到位

首先非常感谢你的回答。你的意思是,我们先启动4,然后_conf初始化为空,然后我再往leader里面添加4,之后再删除3。这样吗?我有以下疑问: 1._conf是允许成员为空的吗? 2.如果当前节点不在_conf里面,是被允许的吗?

Edward-xk commented 3 years ago

因此我们会先启动4,设置成员是1,2,4

你们这种不经过 leader 直接指定 conf 的做法是比较危险的,容易出现脑裂的 case; 建议的做法是新节点起来都是空的配置,然后走配置变更的接口,可以是先加再减,也可以走 change_peers 一步到位

首先非常感谢你的回答。你的意思是,我们先启动4,然后_conf初始化为空,然后我再往leader里面添加4,之后再删除3。这样吗?我有以下疑问: 1._conf是允许成员为空的吗? 2.如果当前节点不在_conf里面,是被允许的吗?

1 和 2 都是可以的。