在保证线性一致性的情况下如何写Kv
要在 Raft 系统中保证 KV 写操作的线性一致性最核心的原则是RPC 收到Put/Append后不能直接修改 KV也不能在写入 Leader 本地日志后立即返回成功必须等命令被 Raft 提交并应用到 KV 状态机后才能返回OK。一、完整写入流程假设客户端发送Put(x, 100) ClientId C7 RequestId 12完整过程应该是客户端发送写请求 ↓ Leader调用Raft::Start() ↓ 写入Leader本地日志 ↓ 复制给Follower ↓ 多数节点复制成功 ↓ 日志变成Committed ↓ 通过applyChan交给KVServer ↓ KVServer检查请求是否重复 ↓ 真正修改KV数据库 ↓ 更新lastRequestId ↓ 通知等待中的RPC线程 ↓ RPC返回OK对这个项目来说最直观的线性化点就是已提交命令在GetCommandFromRaft()中真正应用到 KV 状态机的时刻。二、RPC线程不能直接写KVPutAppend()收到请求后只负责构造命令Op op; op.Operation args-op(); op.Key args-key(); op.Value args-value(); op.ClientId args-clientid(); op.RequestId args-requestid();然后提交给 Raftm_raftNode-Start(op, raftIndex, term, isleader);这里的Start()通常只表示Leader接受了命令并尝试把它追加到Raft日志它不代表命令已经得到多数节点确认 命令已经提交 KV数据库已经修改因此不能这样写m_raftNode-Start(...); reply-set_err(OK); // 错误此时还没有提交否则 Leader 可能刚写入本地日志就宕机命令后来被新 Leader 覆盖但客户端已经收到成功线性一致性就被破坏了。三、真正修改KV的位置项目是在收到 Raft 的ApplyMsg后修改 KVvoid KvServer::GetCommandFromRaft(ApplyMsg message) { Op op; op.parseFromString(message.Command); if (!ifRequestDuplicate(op.ClientId, op.RequestId)) { if (op.Operation Put) { ExecutePutOpOnKVDB(op); } if (op.Operation Append) { ExecuteAppendOpOnKVDB(op); } } SendMessageToWaitChan(op, message.CommandIndex); }对应代码[kvServer.cpp (line 166)](C:/Users/LENOVO/Desktop/KVstorageBaseRaft-cpp-main/src/raftCore/kvServer.cpp:166)这里先去重再执行Raft已经提交 ↓ 检查是否重复 ↓ 修改KV ↓ 通知RPC线程这才是正确的写入路径。四、图片中的timeOutPop()是什么RPC线程把命令交给 Raft 后会通过日志下标找到对应的等待队列chForRaftIndex-timeOutPop( CONSENSUS_TIMEOUT, raftCommitOp );它在等待Raft 应用线程通知我这个日志位置上的命令已经提交并应用了。这里存在两种结果。情况一等待到了Apply消息也就是进入图片的elseif (raftCommitOp.ClientId op.ClientId raftCommitOp.RequestId op.RequestId) { reply-set_err(OK); } else { reply-set_err(ErrWrongLeader); }为什么不能只看到相同的raftIndex就返回成功假设旧 Leader 在日志位置 10 写入index10客户端C7的请求12但还没提交旧 Leader 就失去领导权。新 Leader可能用另一条命令覆盖这个位置index10客户端C9的请求20此时 RPC线程等到了index10的应用通知但应用的不是自己的命令。所以必须检查raftCommitOp.ClientId op.ClientId raftCommitOp.RequestId op.RequestId只有两者都相同才能证明被应用的确实是当前客户端的当前请求然后才能返回OK。五、情况二等待超时图片中的代码是if (!chForRaftIndex-timeOutPop(...)) { if (ifRequestDuplicate(op.ClientId, op.RequestId)) { reply-set_err(OK); } else { reply-set_err(ErrWrongLeader); } }超时只表示RPC线程在规定时间内没有收到Apply通知不表示命令一定失败。命令可能已经成功应用只是Apply通知到达得比较晚 等待队列通知丢失 RPC线程恰好先超时 网络或线程调度发生延迟因此超时后再次检查ifRequestDuplicate(op.ClientId, op.RequestId)它的判断逻辑是return RequestId m_lastRequestId[ClientId];已经执行过如果返回truelastRequestId[C7] 12说明状态机已经执行过这个请求所以可以返回reply-set_err(OK);注意这不是“把重复请求重新执行一次”而是请求已经执行过这次只补发成功响应尚未确认执行如果返回false只能说明目前没有证据证明请求已经应用不能确定它最终会不会提交。因此不能返回OK而是返回一个可重试错误reply-set_err(ErrWrongLeader);这里的ErrWrongLeader不一定真的表示“节点不是 Leader”更多是在告诉客户端当前执行结果不确定请使用相同的ClientId RequestId重试。六、客户端怎么重试客户端创建一个新逻辑请求时只增加一次RequestIdm_requestId; auto requestId m_requestId; while (true) { args.set_clientid(m_clientId); args.set_requestid(requestId); // 不断尝试不同节点 }比如第一次发送(C7, 12) 超时后重试(C7, 12) 换Leader重试(C7, 12)不能变成第一次发送(C7, 12) 第一次重试(C7, 13) 第二次重试(C7, 14)否则服务端会把它们当成三个不同操作导致Append重复执行。七、KV和去重表必须一起更新执行Put时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(); }这里同时更新KV数据 lastRequestId去重信息这是必要的。不能出现KV已经修改 但lastRequestId没有更新否则同一个请求重试时会被再次执行。逻辑上它们应该是状态机的一次原子状态转换(KV状态, 去重状态) ↓ 同时应用一条已提交命令 ↓ (新KV状态, 新去重状态)八、这段代码保证成功写入的依据只有下面两种情况能够返回OK1. 等到了Apply消息并且ClientId、RequestId都匹配 2. 等待超时但去重表证明这个请求已经应用过以下情况不能返回成功刚调用Start() 只写入了Leader本地日志 只知道自己目前是Leader 等待到相同日志下标但不是相同请求 超时且去重表里找不到请求

相关新闻

Raft如何做到线性一致性

Raft如何做到线性一致性

一、为什么需要请求去重考虑一次 Append("name", "A"):1. 客户端发送 Append 请求 2. Leader 将请求提交到 Raft 日志 3. KV 状态机执行成功,name 变成 "A" 4. 服务端返回响应 5. 但响应在网络中丢失 6. 客户端超时&#…

2026/10/16 15:26:02 阅读更多 →
JWT解析工具

JWT解析工具

JWT令牌怎么解码查看?在线JWT解析工具教程 前后端分离项目中,JWT(JSON Web Token)是最常用的身份认证方式。但拿到一串 xxxxx.yyyyy.zzzzz 的 token,根本看不出里面存了什么信息、什么时候过期。本文教你用盘子工具站…

2026/10/18 23:01:10 阅读更多 →
OpenHarmony系统Python3.13.5移植实战指南

OpenHarmony系统Python3.13.5移植实战指南

1. 项目背景与挑战去年在为一个工业物联网项目选型时,客户要求必须在OpenHarmony系统上运行Python数据分析脚本。当时市面上还没有成熟的Python3移植方案,这直接促使我开始了将Python3.13.5移植到OpenHarmony的工作。OpenHarmony作为新一代分布式操作系统…

2026/10/17 3:00:44 阅读更多 →

最新新闻

一站式云原生DevOps平台:打通研发交付全链路

一站式云原生DevOps平台:打通研发交付全链路

简介:软件研发管理平台一站式云原生DevOps解决方案是一份面向企业研发团队、产品经理及DevOps转型人员的系统化演示文稿,重点阐释如何借助敏捷迭代、小步快跑的方式完成产品规划、项目管理、质量跟踪与持续交付,适合用于方案汇报、团队内训和…

2026/10/20 1:21:57 阅读更多 →
Anki 间隔重复完全指南:让每张卡片的复习时间自动排好

Anki 间隔重复完全指南:让每张卡片的复习时间自动排好

Anki 间隔重复完全指南:让每张卡片的复习时间自动排好 【免费下载链接】anki Anki is a smart spaced repetition flashcard program 项目地址: https://gitcode.com/GitHub_Trending/an/anki 每晚背完单词,第二天就忘掉大半,问题不在…

2026/10/20 1:21:57 阅读更多 →
基于ROS的轮式机器人建模与路径规划仿真实践指南

基于ROS的轮式机器人建模与路径规划仿真实践指南

简介:基于ROS的轮式机器人建模与路径规划仿真是哈尔滨师范大学自然科学学报2020年刊发的一篇学术论文(PDF格式),聚焦移动机器人路径规划、自主导航与避障技术。文章以ROS作为机器人开发平台,通过Rviz建立双轮差速机器人…

2026/10/20 1:21:57 阅读更多 →
OpenRocket 实战指南:一枚火箭从建模到弹道落地的完整仿真流程

OpenRocket 实战指南:一枚火箭从建模到弹道落地的完整仿真流程

OpenRocket 实战指南:一枚火箭从建模到弹道落地的完整仿真流程 【免费下载链接】openrocket Model-rocketry aerodynamics and trajectory simulation software 项目地址: https://gitcode.com/GitHub_Trending/op/openrocket OpenRocket 是一款开源火箭仿真…

2026/10/20 1:21:57 阅读更多 →
用调茶构建成长记录系统:具身化行为驱动的神经可塑实践

用调茶构建成长记录系统:具身化行为驱动的神经可塑实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:21:57 阅读更多 →
把 REA 逆向分析的 token 消耗压下来:给 Agent 的搜索与追踪上三道闸门

把 REA 逆向分析的 token 消耗压下来:给 Agent 的搜索与追踪上三道闸门

把 REA 逆向分析的 token 消耗压下来:给 Agent 的搜索与追踪上三道闸门 【免费下载链接】rea Reverse engineer anything with agents, from app behavior down to native binaries. 项目地址: https://gitcode.com/GitHub_Trending/rea2/rea 让 REA 这类 Ag…

2026/10/20 1:20:54 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →