基于Raft分布式Kv存储:AppendEntries
整体调用链Leader.doHeartBeat() ↓ 构造 AppendEntriesArgs Leader.sendAppendEntries() ↓ RPC Follower.AppendEntries() ↓ Follower.AppendEntries1() ↓ 检查任期、匹配日志、追加日志、更新 commitIndex ↓ 返回 AppendEntriesReplyRaft 里同一个AppendEntries RPC同时承担两种功能entries 为空 → 心跳 entries 不为空 → 日志复制这是 Raft 论文中定义的标准行为。请求参数term Leader 当前任期。 leaderId Leader 的节点编号。 prevLogIndex 新日志前面一条日志的下标。 prevLogTerm prevLogIndex 对应日志的任期。 entries[] 要复制的日志可以为空。 leaderCommit Leader 已知的最大提交下标。回复中主要有term Follower 当前任期。 success prevLogIndex 和 prevLogTerm 是否匹配 以及日志是否成功接受。 updateNextIndex 失败时建议 Leader 下一次从哪个下标重试。 appState 项目自定义的 RPC/应用状态。整体伪代码lock(m_mtx); 标记网络和应用层正常; if (leader.term currentTerm) { 拒绝请求; return; } 退出函数前持久化状态; if (leader.term currentTerm) { 更新 currentTerm; 清空 votedFor; 转为 Follower; } 转为 Follower; 重置选举计时器; if (prevLogIndex 超过本地最后日志) { 拒绝并告诉 Leader 本地日志长度; return; } if (prevLogIndex 位于本地快照之前) { 拒绝并建议从快照之后发送; } if (prevLogIndex 和 prevLogTerm 匹配) { 合并 entries; 更新 commitIndex; 返回成功; } else { 查找冲突任期的起始位置; 返回失败和建议的 nextIndex; }源码实现位于Raft::AppendEntries1()一、对整个处理过程加锁std::lock_guardstd::mutex locker(m_mtx);这个锁覆盖整个AppendEntries1()用于保护m_currentTerm m_status m_votedFor m_logs m_commitIndex m_lastResetElectionTime 快照元数据这样日志匹配、日志修改和提交位置更新构成一个原子状态转换不会和投票、快照或另一个AppendEntries同时修改 Raft 状态。二、标记 RPC 已经正常到达reply-set_appstate(AppNormal);Leader 发送前会把appState初始化成类似Disconnected的状态。Follower 进入处理函数后将其改成AppNormal用于区分RPC 根本没有到达和RPC 到达了但 Raft 逻辑拒绝了请求真正判断日志复制结果的字段仍然是success。三、拒绝低任期 Leaderif (args-term() m_currentTerm) { reply-set_success(false); reply-set_term(m_currentTerm); reply-set_updatenextindex(-100); return; }例如Follower.currentTerm 8 请求.term 7说明发送请求的是过期 LeaderFollower 必须拒绝。这里不会重置选举计时器。否则旧 Leader 持续发送过期心跳就可能阻止 Follower 发起新选举。Raft 接收规则也明确要求低任期请求返回失败。-100是项目自定义的哨兵值表示这次拒绝不是日志位置问题Leader 不应根据该回复调整nextIndex。四、设置延迟持久化DEFER { persist(); };它出现在低任期检查之后因此低任期请求 → 不改变状态不持久化 当前或更高任期请求 → 函数返回前执行 persist()这保证currentTerm、votedFor和日志变更在回复 Leader 前进入持久化状态符合 Raft 对持久状态的要求。不过当前实现会对正常的空心跳也执行persist()。如果persist()每次都序列化并写入完整日志这会带来明显的周期性磁盘开销可以根据“持久状态是否真的发生变化”决定是否写入。五、接受更高任期if (args-term() m_currentTerm) { m_status Follower; m_currentTerm args-term(); m_votedFor -1; }例如本地是 term7 的 Candidate 收到 term8 的 AppendEntries本地节点由此得知集群已经进入 term 8必须更新任期 取消旧任期投票 退回 Follower此处没有立即返回因为更高任期的请求仍然可能携带合法日志应继续尝试接收。六、同任期也转为 Followerm_status Follower; m_lastResetElectionTime now();Candidate 可能因为网络延迟在同一任期内收到合法 Leader 的心跳。此时 Candidate 应承认该 Leader转为 Follower。选举计时器在日志匹配之前就被重置。这意味着即使日志因为prevLogTerm不匹配而被拒绝只要发送方具有合法的当前任期Follower 仍然承认它是当前 Leader不会因为日志修复需要几轮 RPC 就错误发起选举。七、Follower 日志太短if (args-prevlogindex() getLastLogIndex()) { reply-set_success(false); reply-set_term(m_currentTerm); reply-set_updatenextindex(getLastLogIndex() 1); return; }例如Leader 请求 prevLogIndex 10 Follower lastLogIndex 6Follower 根本没有日志 10无法验证prevLogTerm于是回复success false updateNextIndex 7Leader 下一轮就可以从日志 7 开始发送而不是每次只把nextIndex减一。八、请求位置早于本地快照else if ( args-prevlogindex() m_lastSnapshotIncludeIndex ) { reply-set_success(false); reply-set_term(m_currentTerm); reply-set_updatenextindex( m_lastSnapshotIncludeIndex 1 ); }例如 Follower 已经生成快照snapshotIndex 100但收到prevLogIndex 80日志 80 已被压缩Follower 无法再通过普通日志数组匹配它因此建议 Leader 从快照之后开始这里源码缺少一个return设置失败回复后代码仍然会继续调用matchLog(prevLogIndex, prevLogTerm)而matchLog()要求下标不能小于快照位置。这可能触发断言或非法访问。这里应当补上return;这是当前实现中一个明确的控制流问题。九、检查前置日志是否匹配matchLog( args-prevlogindex(), args-prevlogterm() )匹配规则是prevLogIndex snapshotIndex → 和 snapshotTerm 比较 prevLogIndex 在普通日志中 → 和对应日志的 term 比较 下标不存在或 term 不同 → 匹配失败prevLogIndex prevLogTerm相当于 Leader 给出的连接点。只有连接点匹配Follower 才能安全接受后续entries。例如Leader index 4 5 6 7 term 2 2 3 3 请求 prevLogIndex 5 prevLogTerm 2 entries [6, 7]Follower 必须先确认自己的日志 5 也是任期 2。十、匹配成功后合并日志代码逐条处理entries新日志下标超过本地最后日志 → push_back() 本地已经存在相同下标 → 比较 term → term 不同则替换如果同一个index和term对应的命令却不同代码会触发断言same index same term different commandRaft 的日志匹配性质保证两份日志只要拥有相同下标和任期它们之前的日志以及该条命令都应相同。因此出现这种情况通常意味着实现或持久化数据已经损坏。标准 Raft 在发现“相同下标、不同任期”时会删除冲突条目以及它后面的所有日志再追加 Leader 日志。当前代码采用逐项覆盖方式没有明确截断冲突后的整个后缀这与论文中的标准步骤存在差异需要特别验证乱序请求和 Follower 多余后缀的行为。十一、 更新commitIndexif (args-leadercommit() m_commitIndex) { m_commitIndex std::min( args-leadercommit(), getLastLogIndex() ); }Follower 的提交位置只能前进不能后退。之所以取最小值是因为 Leader 可能已经提交到日志 20但当前 Follower 只同步到日志 16leaderCommit 20 Follower.lastLogIndex 16 Follower.commitIndex 16Follower 不能提交自己尚未拥有的日志。这里只更新commitIndex并不直接执行日志。之后applierTicker()会发现lastApplied commitIndex再按顺序把已提交日志交给上层状态机。十二、匹配失败时快速回退如果prevLogIndex存在但任期不匹配代码会找到 Follower 当前冲突任期的第一条日志。例如Follower index 1 2 3 4 5 6 7 term 1 1 2 2 4 4 4 Leader 请求 prevLogIndex 7 prevLogTerm 3Follower 的日志 7 属于任期 4不是任期 3。它向前扫描整个任期 4日志 7 → term 4 日志 6 → term 4 日志 5 → term 4 日志 4 → term 2停止于是建议updateNextIndex 5Leader 可以直接从冲突任期的开头重试而不是依次尝试 7、6、5减少 RPC 次数。

相关新闻

MATLAB 2019b卸载卡死?从原理到实战的完整解决方案

MATLAB 2019b卸载卡死?从原理到实战的完整解决方案

1. 问题缘起:当卸载变成一场“持久战”如果你也曾在Windows系统上试图卸载MATLAB 2019b,却眼睁睁看着进度条卡在某个地方纹丝不动,或者那个熟悉的uninstall.exe窗口直接失去响应,那么你绝不是一个人。这几乎成了这款特定版本软件的…

2026/7/29 10:43:33阅读更多 →
ESP32 I2S音频输出实战:驱动NS4168数字功放实现智能音频系统

ESP32 I2S音频输出实战:驱动NS4168数字功放实现智能音频系统

1. 项目缘起:当ESP32遇上音频放大器最近在折腾一个智能家居的小项目,想给家里的一个旧音箱加上语音控制和网络电台播放功能。核心的音频处理部分,我自然想到了ESP32这颗“万金油”芯片,它内置的I2S接口处理数字音频流非常方便。但…

2026/7/29 10:43:33阅读更多 →
基于行空板K10与BH1750传感器构建智能光照培养监测系统

基于行空板K10与BH1750传感器构建智能光照培养监测系统

1. 项目缘起:当开源硬件遇上经典生物实验 作为一名长期混迹于创客圈和STEM教育领域的“老炮儿”,我见过太多用Arduino、树莓派做的小玩意儿,从智能浇花到环境监测,创意层出不穷。但说实话,很多项目要么停留在“让灯亮起…

2026/7/29 10:43:33阅读更多 →
电商SCRM系统怎么选?从订单打通到复购运营

电商SCRM系统怎么选?从订单打通到复购运营

电商品牌选择SCRM系统时,订单数据打通能力应当成为核心考察指标。原因很直接:企业微信里的客户关系,只能说明“这个人加了谁、进入了哪个群”;订单数据则能进一步回答“他买过什么、何时购买、消费多少、是否复购”。艾客SCRM将电…

2026/7/29 20:53:42阅读更多 →
大气层整合包:Nintendo Switch自制系统的终极实战指南

大气层整合包:Nintendo Switch自制系统的终极实战指南

大气层整合包:Nintendo Switch自制系统的终极实战指南 【免费下载链接】Atmosphere-stable 大气层整合包系统稳定版 项目地址: https://gitcode.com/gh_mirrors/at/Atmosphere-stable 欢迎来到Nintendo Switch自制系统的世界!大气层整合包&#x…

2026/7/29 20:53:42阅读更多 →
ASP.NET Core中集成MonkeyCache:提升Web应用响应速度的终极指南

ASP.NET Core中集成MonkeyCache:提升Web应用响应速度的终极指南

ASP.NET Core中集成MonkeyCache:提升Web应用响应速度的终极指南 【免费下载链接】monkey-cache Easily cache any data structure for a specific amount of time in any .NET application. 项目地址: https://gitcode.com/gh_mirrors/mo/monkey-cache Monke…

2026/7/29 20:53:42阅读更多 →
量化投资策略诊断:用Pyfolio将数据洞察转化为决策优势

量化投资策略诊断:用Pyfolio将数据洞察转化为决策优势

量化投资策略诊断:用Pyfolio将数据洞察转化为决策优势 【免费下载链接】pyfolio Portfolio and risk analytics in Python 项目地址: https://gitcode.com/gh_mirrors/py/pyfolio 量化投资策略开发过程中,最令人头疼的不是策略设计本身&#xff0…

2026/7/29 20:53:42阅读更多 →
当需求跑赢产能,谁来重建数据研发的生产线?奇点智能DataAGI给出解题思路

当需求跑赢产能,谁来重建数据研发的生产线?奇点智能DataAGI给出解题思路

企业的数据需求正变得越来越多、越来越急、越来越复杂,但这些需求最终都要压在少数几位数据专家身上。专家真正稀缺的能力是判断力,可大量时间却被查找、整理、编写、核验这类重复性工作占据,判断力因此成了最容易被挤占的部分。如果这些重复…

2026/7/29 20:53:42阅读更多 →
React Native Modern Datepicker完全指南:打造高颜值跨平台日期选择器

React Native Modern Datepicker完全指南:打造高颜值跨平台日期选择器

React Native Modern Datepicker完全指南:打造高颜值跨平台日期选择器 【免费下载链接】react-native-modern-datepicker A customizable calendar, time & month picker for React Native (including Persian Jalaali calendar & locale) 项目地址: http…

2026/7/29 20:51:42阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/29 9:47:45阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/29 7:00:19阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/29 7:58:51阅读更多 →
28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“!

28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“!

28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“! 在构建复杂的 Agent 系统时,我们经常会遇到这样的场景:Agent 正在执行一个多步骤的任务,比如“下单购买商品”,但执行到一半时,我们…

2026/7/29 0:01:46阅读更多 →
自律同行,突破无界!NANK南卡正式官宣曾舜晞成为品牌代言人

自律同行,突破无界!NANK南卡正式官宣曾舜晞成为品牌代言人

近日,国际专注开放式技术研发的声学品牌Nank南卡,正式官宣实力艺人曾舜晞担任品牌代言人。消息一经发出便轰动全网。为什么耳机品牌不选择流量明星、老牌歌手?而且是选择曾舜晞?让我们一起来探索一下!比起短期的流量&a…

2026/7/29 0:01:46阅读更多 →
【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

一、本文介绍 🔥本文在RT-DETR多模态融合目标检测中引入RLAB残差线性注意力模块,可在不同模态特征交互阶段进行多次残差细化,使可见光、红外等特征在尺度、语义和空间位置上更好对齐;随后将细化特征与解码器输出拼接并生成Q、K、V,通过线性注意力自适应强化关键通道、目…

2026/7/29 0:01:46阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/28 20:22:24阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/29 4:31:51阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/29 14:26:42阅读更多 →