基于Raft分布式Kv存储:RPC
在这个项目里RPC 可以理解为整个分布式 KV 系统的“远程通信层”。它负责让不同进程、不同端口上的对象能够互相调用方法。RPC 本身不实现 Raft 算法也不存储 KV 数据它负责把请求送过去、调用正确的方法再把结果送回来。一、项目中有两类 RPC客户端 Clerk │ Get / Put / Append ▼ KVServer │ RequestVote / AppendEntries / InstallSnapshot ▼ 其他 Raft 节点对应两份.proto通信双方RPC 服务方法Clerk → KVServerkvServerRpcGet、PutAppendRaft → RaftraftRpcRequestVote、AppendEntries、InstallSnapshot1. Clerk 与 KVServer 之间的 RPC接口定义在 [kvServerRPC.proto (line 43)](C:/Users/LENOVO/Desktop/KVstorageBaseRaft-cpp-main/src/raftRpcPro/kvServerRPC.proto:43)service kvServerRpc { rpc PutAppend(PutAppendArgs) returns(PutAppendReply); rpc Get(GetArgs) returns(GetReply); }它负责把用户的 KV 操作发送给远程服务器。GetRPC客户端请求message GetArgs { bytes Key 1; bytes ClientId 2; int32 RequestId 3; }作用分别是Key要查询的键。ClientId客户端唯一标识。RequestId该客户端的请求序号用于重试和去重。bool ok m_servers[server]-Get(args, reply);这个调用看起来像普通 C 函数但m_servers[server]代表远程服务器实际会经过网络发送。PutAppendRPC客户端可以发起两种修改Put(key, value); Append(key, value);最终都被转换成PutAppend(key, value, Put); PutAppend(key, value, Append);请求中包含message PutAppendArgs { bytes Key 1; bytes Value 2; bytes Op 3; bytes ClientId 4; int32 RequestId 5; }ClientId RequestId很重要。因为 RPC 可能超时客户端可能重发同一个请求。如果没有请求编号一个Append请求重试两次就可能真的追加两次。RPC 负责传递编号KVServer 负责判断是否重复执行。2. RPC 帮助客户端寻找 LeaderClerk 一开始不一定知道哪个服务器是 Leader。在 [clerk.cpp (line 21)](C:/Users/LENOVO/Desktop/KVstorageBaseRaft-cpp-main/src/raftClerk/clerk.cpp:21) 中它会循环请求服务器bool ok m_servers[server]-Get(args, reply); if (!ok || reply.err() ErrWrongLeader) { server (server 1) % m_servers.size(); continue; }这里有两种失败!okRPC 通信失败例如连接失败、服务器宕机。ErrWrongLeader网络通信成功但请求发给了 Follower。这两种失败不能混为一谈。ok true只表示请求成功发出并成功收到了可解析的响应不表示业务操作一定成功。Clerk 会继续尝试其他服务器找到 Leader 后缓存其编号到m_recentLeaderId下次优先联系它。3. KV 请求最终会进入 RaftKVServer 收到PutAppendRPC 后不会直接修改本地数据库。Op op; op.Operation args-op(); op.Key args-key(); op.Value args-value(); op.ClientId args-clientid(); op.RequestId args-requestid(); m_raftNode-Start(op, raftIndex, term, isLeader);执行过程是Clerk 发起 Put RPC ↓ Leader KVServer 收到请求 ↓ 把请求转换成 Op ↓ Raft::Start() 写入 Leader 日志 ↓ 通过 AppendEntries RPC 复制到其他节点 ↓ 多数节点复制成功 ↓ 日志提交并发送到 applyCh ↓ KVServer 执行 Put ↓ 通过 RPC 向 Clerk 返回成功所以客户端 RPC 和 Raft RPC 是串联起来的。读取也经过共识顺序有助于提供线性一致性读取。二、Raft 节点之间的 RPCservice raftRpc { rpc AppendEntries(AppendEntriesArgs) returns(AppendEntriesReply); rpc InstallSnapshot(InstallSnapshotRequest) returns(InstallSnapshotResponse); rpc RequestVote(RequestVoteArgs) returns(RequestVoteReply); }这三个 RPC 基本覆盖了 Raft 节点间的全部通信。1.RequestVote选举 Leader当 Follower 长时间没有收到 Leader 心跳就会Follower ↓ 选举超时 Candidate ↓ currentTerm 向所有其他节点发送 RequestVote RPC请求携带Term CandidateId LastLogIndex LastLogTerm接收节点检查Candidate 的任期是否足够新。当前任期是否已经投票。Candidate 的日志是否至少和自己一样新。响应包含Term VoteGranted候选人获得超过半数的票后成为 Leader。没有RequestVoteRPC各节点就无法跨进程完成投票和 Leader 选举。2.AppendEntries心跳和日志复制这是项目里使用最频繁的 Raft RPC作用有两个。作为心跳Leader 周期性发送没有日志的AppendEntriesEntries 空它告诉 FollowerLeader 还活着不要发起新选举。Follower 收到合法心跳后会重置选举定时器。作为日志复制客户端提交命令后Leader 把日志通过AppendEntries发给 FollowerTerm LeaderId PrevLogIndex PrevLogTerm Entries LeaderCommitFollower 检查上一条日志是否匹配本地 PrevLogIndex 位置的 term 请求中的 PrevLogTerm匹配则追加日志不匹配则返回失败。Leader 根据返回结果更新m_nextIndex[server] m_matchIndex[server]如果复制失败Leader 会调整nextIndex再次发送更早的日志。当一条日志被多数节点确认后Leader 推进commitIndex这条命令才真正提交。3.InstallSnapshot同步快照如果某个 Follower 落后太多Leader 需要的旧日志可能已经被压缩成快照。这时不能再用普通AppendEntries补日志而要发送InstallSnapshot RPC请求携带LeaderId Term LastSnapShotIncludeIndex LastSnapShotIncludeTerm Data其中Data是 KV 数据、客户端去重信息等序列化后的快照。Follower 收到后会安装快照数据。删除快照覆盖的旧日志。更新快照索引和任期。更新commitIndex、lastApplied。把快照交给上层 KVServer 恢复状态。它解决的是“落后节点快速追赶”的问题。三、底层 RPC 框架具体做了什么业务代码只需要写stub-AppendEntries(controller, args, response, nullptr);底层实际完成了很多工作。1. 定义统一消息格式message RpcHeader { bytes service_name 1; bytes method_name 2; uint32 args_size 3; }一次请求大致是Header长度 RpcHeader protobuf序列化后的请求参数例如service_name raftRpc method_name AppendEntries args_size 120 args AppendEntriesArgs的二进制数据2. 客户端序列化并发送从方法描述符获取服务名和方法名。序列化请求参数。构造 RPC 请求头。连接目标 IP 和端口。通过 TCP 发送数据。阻塞等待响应。将响应反序列化到reply。通过RpcController记录通信错误。3. 服务端注册和查找服务KVServer 启动时同时注册两个服务provider.NotifyService(this); provider.NotifyService(this-m_raftNode.get());也就是KvServer对象 → Get、PutAppend Raft对象 → RequestVote、AppendEntries、InstallSnapshotRpcProvider保存服务名、方法名、服务对象之间的映射。4. 服务端反序列化和方法分发解析 RpcHeader ↓ 得到 service_name ↓ 得到 method_name ↓ 找到注册的 Service 对象 ↓ 创建对应的 request 和 response ↓ 反序列化 request ↓ service-CallMethod(...)protobuf 生成的CallMethod再把请求分发到正确的重写方法。5. 把响应发回来业务函数填写response后执行done-Run();它会调用RpcProvider::SendRpcResponse(...)将响应序列化并通过 TCP 发送给调用者。四、RPC 不负责什么RPC 只是通信机制它不负责决定谁是 Leader。判断是否应该投票。检查日志是否匹配。决定日志何时提交。修改 KV 数据。处理重复客户端请求。制作或应用快照。这些分别由 Raft、KVServer 和 Clerk 的业务逻辑负责。最准确的划分是RPC把某个对象的方法调用跨网络送到另一个进程 Raft保证多个节点对命令顺序达成一致 KVServer执行命令并维护键值数据 Clerk发起请求、寻找 Leader、失败重试

相关新闻

AVRDUDESS终极指南:3步轻松搞定AVR单片机编程

AVRDUDESS终极指南:3步轻松搞定AVR单片机编程

AVRDUDESS终极指南:3步轻松搞定AVR单片机编程 【免费下载链接】AVRDUDESS A GUI for AVRDUDE 项目地址: https://gitcode.com/gh_mirrors/avr/AVRDUDESS AVRDUDESS是一款功能强大的AVR编程器图形界面工具,专为简化AVRDUDE命令行工具而设计。无论你…

2026/11/4 0:36:15 阅读更多 →
DeepChem:用AI解锁高分子材料科学的未来密码

DeepChem:用AI解锁高分子材料科学的未来密码

DeepChem:用AI解锁高分子材料科学的未来密码 【免费下载链接】deepchem Democratizing Deep-Learning for Drug Discovery, Quantum Chemistry, Materials Science and Biology 项目地址: https://gitcode.com/GitHub_Trending/de/deepchem DeepChem&#xf…

2026/11/4 0:36:48 阅读更多 →
本地智能办公工具 OpenClaw v2.7.9 分步部署教学 小白友好(含安装包)

本地智能办公工具 OpenClaw v2.7.9 分步部署教学 小白友好(含安装包)

OpenClaw 一键安装包|一键部署,告别复杂环境配置 适配系统:Windows10/11 64 位 当前版本:v2.7.9(虾壳云版) 核心优势:全程可视化操作,不用命令行、不用手动配置 Python/Node.js&…

2026/11/2 13:50:13 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/3 1:09:25 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/3 10:57:27 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/3 11:35:49 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/3 2:27:21 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/3 10:47:27 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/3 10:57:33 阅读更多 →

日新闻

周新闻

月新闻