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

状态机空闲的时候无法恢复follower #340

Open CodeTrek opened 2 years ago

CodeTrek commented 2 years ago

场景: 有一个3副本复制组分别在A、B、C机器上,在里面apply一些日志,保持这个复制组空闲(即不要提交任何日志)。 杀掉其中的一台follower,同时删掉本地数据,然后重启服务,然后这个节点会一直报“reject term_unmatched AppendEnteries from ...”。

问题原因: Replicator::_on_heartbeat_returned中没有处理!response->success()的场景,导致即使follower因为term不对返回了false,leader也不处理。同时因为复制组内没有append新日志,所有Replicator::_send_entries不会调用。 上述原因导致leader并不知道follower的数据已经丢失,这个状态会一直维持到这个复制组内有新的数据提交为止(由_send_entries来触发)。

解决方案: Replicator::_on_heartbeat_returned处理一下!response->success()的情况。 在braft没有解决这个问题前,业务层可以通过定期往复制组提交一条心跳日志或者follower启动后通过leader往复制组里提交一条log驱动leader发现follower的数据已经丢失。

wangxun155423 commented 2 years ago

本质在于你这个场景操作是非法的,不能强删本地数据,里面会有raft组元信息等配置,这个是不允许的,下线机器只能通过change_peers完成

CodeTrek commented 2 years ago

这个场景其实模拟的是机器宕机后磁盘损坏然后替换了一块新磁盘上去的情况,这种应该是现实存在的吧

ehds commented 2 years ago

可以参考 https://github.com/baidu/braft/issues/292 你说的这种情况是存在的,正确的做法应该是先移除这个节点,然后再加入这个节点。