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.84k stars 862 forks source link

如果没有新增数据是否会每次启动时重复发送快照? #459

Open cangfengzhs opened 1 week ago

cangfengzhs commented 1 week ago

LogManager中的_last_snapshot_id并没有持久化,所以每次启动时_last_snapshot_id都为0

在以下场景中:

  1. ABC三副本
  2. AB启动后写入数据
  3. AB停止写入数据
  4. 启动C
  5. leader向C发送快照
  6. ABC全部重启,并且A或B选为Leader
  7. Leader向C写入become leader时的那个config时,C中没有任何的Log。所以对于任意的Index,get_term时返回的都是0,,会再触发一次snapshot。

不知道上述场景理解的正不正确。如果正确的话是不是意味着如果没有新增数据C每次重启时都要收一遍snapshot?

ehds commented 1 week ago

重启后会先加载本地 snapshot (如果存在的话), 加载成功后会更新 LogManager 中的 _last_snapshot_id。 具体你看下具体的代码:

node 启动的时候初始化时,会调用 _snapshot_executor 的初始化。 https://github.com/baidu/braft/blob/bc9fb052868560322a9b833c8179bb4d1a1f7dc5/src/braft/node.cpp#L270

会注册一个 FirstSnapshotLoadDone 的任务 https://github.com/baidu/braft/blob/bc9fb052868560322a9b833c8179bb4d1a1f7dc5/src/braft/snapshot_executor.cpp#L391-L392

如果成功,则更新 _log_manager 的 _last_snapshot_id https://github.com/baidu/braft/blob/bc9fb052868560322a9b833c8179bb4d1a1f7dc5/src/braft/snapshot_executor.cpp#L256

cangfengzhs commented 1 week ago

我理解在加载完snapshot之后相关资源会被清理掉。那么第二次启动的时候并没有snapshot存在,这个时候怎么处理?

ehds commented 1 week ago

我理解在加载完snapshot之后相关资源会被清理掉。

你指的 “相关资源清理掉” 的相关资源具体是指什么。 braft 节点会接收 leader 的快照,同时自身也会打快照。如果有快照产生,每个节点会保留至少一个最新的版本。

那么第二次启动的时候并没有snapshot存在,这个时候怎么处理?

如果之前产生过快照,每次重新启动都至少有一个快照存在本地,启动时会预先加载。除非用户自行强行删除,否则不存在产生了了快照,“那么第二次启动的时候并没有snapshot存在” 这种情况,否则会破坏 raft 协议的安全性要求。

cangfengzhs commented 1 week ago

在测试,模拟一个副本数据完全丢失的情况。所以手动强行删除了一个副本上的所有数据

ehds commented 1 week ago

模拟一个副本数据完全丢失

安全的做法是先从集群移除该节点(remove_peer), 清空该节点的持久化状态,重新 add_peer 进来 (最好是改变 peer_id 的 index,与原先区别)。

如果正确的话是不是意味着如果没有新增数据C每次重启时都要收一遍snapshot?

如果你这里的重启都是指的是删除所有数据,那么每次节点的状态都是空,是会做一遍 snapshot.

cangfengzhs commented 1 week ago

模拟故障,所以不太好按照安全的做法处理。

只删一次数据,然后多次重启。