第二天__


持久化

持久化的内容为两部分:1.raft节点的部分信息;2.kvDb的快照

raft节点的部分信息

m_currentTerm :当前节点的Term,避免重复到一个Term,可能会遇到重复投票等问题。
m_votedFor :当前Term给谁投过票,避免故障后重复投票。
m_logs :raft节点保存的全部的日志信息。

kvDb的快照
m_lastSnapshotIncludeIndex :快照的信息,快照最新包含哪个日志Index
m_lastSnapshotIncludeTerm :快照的信息,快照最新包含哪个日志Term,与m_lastSnapshotIncludeIndex 是对应的。

Snapshot是kvDb的快照,也可以看成是日志,因此:全部的日志 = m_logs + snapshot
因为Snapshot是kvDB生成的,kvDB肯定不知道raft的存在,而什么term、什么日志Index都是raft才有的概念,因此snapshot中肯定没有term和index信息。所以需要raft自己来保存这些信息。故,快照与m_logs联合起来理解即可。

为什么持久化?

需要持久化的内容发送改变的时候就要注意持久化。
比如term 增加,日志增加等等。
具体的可以查看代码仓库中的void Raft::persist() 相关内容。

void Raft::persist() {
  // Your code here (2C).
  auto data = persistData();
  m_persister->SaveRaftState(data);
  // fmt.Printf("RaftNode[%d] persist starts, currentTerm[%d] voteFor[%d] log[%v]\n", rf.me, rf.currentTerm,
  // rf.votedFor, rf.logs) fmt.Printf("%v\n", string(data))
}
std::string Raft::persistData() {
  BoostPersistRaftNode boostPersistRaftNode;
  boostPersistRaftNode.m_currentTerm = m_currentTerm;
  boostPersistRaftNode.m_votedFor = m_votedFor;
  boostPersistRaftNode.m_lastSnapshotIncludeIndex = m_lastSnapshotIncludeIndex;
  boostPersistRaftNode.m_lastSnapshotIncludeTerm = m_lastSnapshotIncludeTerm;
  for (auto& item : m_logs) {
    boostPersistRaftNode.m_logs.push_back(item.SerializeAsString());
  }

  std::stringstream ss;
  boost::archive::text_oarchive oa(ss);
  oa << boostPersistRaftNode;
  return ss.str();
}
void Persister::SaveRaftState(const std::string &data) {
  std::lock_guard<std::mutex> lg(m_mtx);
  // 将raftstate和snapshot写入本地文件
  clearRaftState();
  m_raftStateOutStream << data;
  m_raftStateSize += data.size();
}

Raft::persistData() 函数收集 Raft 节点的当前状态(包括当前任期、投票信息、日志等),使用 Boost 库将这些状态序列化为一个字符串形式。Raft::persist() 调用 persistData() 获取序列化后的数据,然后通过 m_persister->SaveRaftState(data) 将该数据传递给 Persister 对象保存。
Persister::SaveRaftState() 使用输出流将数据写入持久化存储,确保在系统崩溃时可以从这些存储的数据中恢复。

谁调用初始化

谁来调用都可以,只要能保证需要持久化的内容能正确持久化。
仓库代码中选择的是raft类自己来完成持久化。因为raft类最方便感知自己的term之类的信息有没有变化。
注意,虽然持久化很耗时,但是持久化这些内容的时候不要放开锁,以防其他线程改变了这些值,导致其它异常。

其实持久化是一个非常难的事情,因为持久化需要考虑:速度、大小、二进制安全。
因此仓库实现目前采用的是使用boost库中的持久化实现,将需要持久化的数据序列化转成std::string 类型再写入磁盘。

kvServer

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值