基于Raft分布式Kv存储:Kvserver怎么与上层KvDB沟通? 这里需要先澄清项目里的“上层 KVDB”并不是独立进程也没有通过 RPC 与KvServer通信。KVDB 就是KvServer内部持有的跳表对象class KvServer { private: SkipListstd::string, std::string m_skipList; };因此两者通过普通的 C 成员函数调用沟通。mermaid flowchart TD C[Clerk 客户端] --|RPC| K[KvServer RPC 接口] K --|Start(Op)| R[本机 Raft] R --|已提交 ApplyMsg| AC[applyChan] AC -- A[KvServer 应用线程] A --|insert_set_element| DB[跳表 KVDB] K --|search_element| DB 写操作客户端发送 Put 后Clerk → KvServer::PutAppend() → Raft::Start(op) → Raft 集群复制并提交日志 → applyChan → KvServer::GetCommandFromRaft() → ExecutePutOpOnKVDB() → m_skipList.insert_set_element()关键代码void KvServer::ExecutePutOpOnKVDB(Op op) { m_mtx.lock(); m_skipList.insert_set_element(op.Key, op.Value); m_lastRequestId[op.ClientId] op.RequestId; m_mtx.unlock(); }见 [kvServer.cpp (line 66)](/C:/Users/LENOVO/Desktop/KVstorageBaseRaft-cpp-main/src/raftCore/kvServer.cpp:66)。最重要的一点是KvServer 收到 Put RPC 后不会立即写跳表必须等 Raft 日志提交后才能写。Raft 如何通知 KvServerKvServer和本机Raft共享一个队列std::shared_ptrLockQueueApplyMsg applyChan;初始化 Raft 时传进去m_raftNode-init(servers, m_me, persister, applyChan);Raft 提交日志后执行applyChan-Push(message);KvServer 一直阻塞读取void KvServer::ReadRaftApplyCommandLoop() { while (true) { auto message applyChan-Pop(); if (message.CommandValid) { GetCommandFromRaft(message); } if (message.SnapshotValid) { GetSnapShotFromRaft(message); } } }见 [kvServer.cpp (line 281)](/C:/Users/LENOVO/Desktop/KVstorageBaseRaft-cpp-main/src/raftCore/kvServer.cpp:281)。随后GetCommandFromRaft()解析Op并修改 KVDBif (!ifRequestDuplicate(op.ClientId, op.RequestId)) { if (op.Operation Put) { ExecutePutOpOnKVDB(op); } if (op.Operation Append) { ExecuteAppendOpOnKVDB(op); } }读操作Get 也先进入 Raft提交后唤醒等待的 RPC 线程最后直接查询跳表m_skipList.search_element(op.Key, *value);对应流程KvServer::Get() → Raft::Start(GetOp) → 等待该日志提交 → ExecuteGetOpOnKVDB() → m_skipList.search_element() → 返回 valueGet 进入 Raft 的目的是保证读取发生在之前已经提交的写操作之后提供线性一致读。快照通信KvServer 制作快照时直接调用跳表m_serializedKVData m_skipList.dump_file();恢复快照时m_skipList.load_file(m_serializedKVData);所以 KvServer 和 KVDB 之间有三类直接调用写入insert_set_element(key, value) 读取search_element(key, value) 快照dump_file() / load_file()