Raft协议实现数据的分布式存储

发布时间:2026/9/15 14:44:24

Raft协议实现数据的分布式存储 Raft 是一种分布式共识协议。它本身不直接负责把数据存入磁盘而是保证多个节点按照相同顺序执行相同的操作从而让多个节点拥有一致的数据副本。可以把它理解为客户端命令 ↓ Raft 复制日志 ↓ 多个节点按相同顺序执行日志 ↓ 每个节点得到相同的 KV 数据例如PUT user:1001 {name:张三}Raft 要保证所有副本最终都按同样的顺序执行这条命令。一、Raft 实现分布式存储的总体结构一个基于 Raft 的 KV 存储系统通常分为四层客户端 │ ▼ 请求路由层 │ ▼ Raft 共识层 │ ▼ 状态机层 │ ▼ 本地存储引擎具体来说1. 客户端层客户端发送PUT(user:1001, 张三) GET(user:1001)2. Raft 层Raft 负责选举 Leader复制操作日志确认多数节点已经保存日志保证日志顺序一致处理节点故障和 Leader 故障3. 状态机层状态机负责真正执行命令PUT user:1001 张三执行后变成内存状态 user:1001 → 张三4. 本地存储层每个节点可以将 Raft 日志和状态机数据保存到本地磁盘例如WAL 日志SSTableB 树RocksDBLevelDB自定义文件Raft 保证的是“大家执行的命令相同”本地存储引擎负责“如何保存这些命令产生的数据”。二、Raft 集群中的三种角色Raft 节点有三种角色Follower 跟随者 Candidate 候选者 Leader 领导者1. FollowerFollower 不主动处理普通写请求主要负责接收 Leader 的心跳接收 Leader 的日志投票选举保存日志执行已经提交的日志2. Candidate当 Follower 长时间没有收到 Leader 的消息时会认为 Leader 可能失效转换为 Candidate开始发起选举。3. LeaderLeader 负责接收客户端请求追加日志向 Followers复制日志判断日志是否提交通知 Followers 执行日志正常情况下客户端只需要和 Leader 通信。三、写入数据的完整流程假设客户端执行PUT user:1001 {name:张三,age:25}集群结构客户端 │ ▼ Node A Leader / \ ▼ ▼ Node B Node C Follower Follower第一步客户端找到 Leader客户端可能首先连接到 Node B但 B 是 Follower。B 可以返回 Leader 地址将请求转发给 Leader直接拒绝并提示客户端重试最终请求到达 Node A。PUT user:1001 ... │ ▼ Node A Leader第二步Leader 将命令写入日志Leader 不会马上直接修改最终 KV 状态而是先将命令追加到本地日志日志 index term command ----------------------------------------------- 1 3 SET config:x 1 2 4 PUT user:1001 张三 3 5 PUT user:1001 {name:张三,age:25}日志中的几个重要字段Index日志条目的位置1、2、3、4……Term写入这条日志时 Leader 所处的任期。Command真正要执行的操作PUT user:1001 ... DELETE user:1001 INCR stock:1001第三步Leader 向 Followers 复制日志Leader 向 B、C 发送日志A ──日志 index3── B A ──日志 index3── CFollower 收到后会先写入自己的本地日志。Node B保存 index3 Node C保存 index3Follower 此时通常还不能立即执行这条命令因为这条日志还没有被 Leader 确认提交。第四步等待多数节点确认假设 B 成功保存C 暂时宕机A保存成功 B保存成功 C没有响应三个节点中有两个节点已经保存A B 2达到多数派因此该日志可以提交。commitIndex 3第五步Leader 执行状态机Leader 将已经提交的日志交给状态机执行PUT user:1001 {name:张三,age:25}状态机执行后KV 数据 user:1001 → {name:张三,age:25}然后 Leader 向客户端返回成功OK第六步通知 Followers 执行Leader 会在后续心跳或日志同步消息中告诉 FollowersleaderCommit 3B 看到leaderCommit3后也执行 index3Node B user:1001 → {name:张三,age:25}C 恢复后Leader 会先把缺少的日志补给 CC 再执行这些已经提交的命令。四、Raft 中的“提交”和“应用”不是一回事这是一个很重要的概念。日志复制成功表示日志已经保存在足够多的节点上。A、B 已保存 index10日志提交表示 Leader 确认它已经不会丢失commitIndex 10状态机应用表示节点真正执行了命令user:1001 → 张三流程是日志写入 ↓ 达到多数派 ↓ 日志提交 ↓ 状态机应用 ↓ KV 数据发生变化通常每个节点维护两个位置commitIndex已经提交到哪里 lastApplied已经执行到哪里要求lastApplied commitIndex节点会持续将lastApplied 1到commitIndex之间的日志交给状态机执行。五、KV 数据如何与 Raft 状态机结合Raft 只处理命令不直接理解 KV 业务。例如客户端发来PUT user:1 张三系统可以把它编码成Command { type: PUT, key: user:1, value: 张三 }Leader 将这个 Command 写入 Raft 日志LogEntry { index: 10, term: 7, command: PUT user:1 张三 }当日志提交后每个节点都调用相同的状态机stateMachine.apply(command)伪代码可以表示为function apply(command): if command.type PUT: kv[command.key] command.value if command.type DELETE: delete kv[command.key] if command.type INCR: kv[command.key] command.amount由于所有节点拥有相同的日志所有节点按照相同顺序执行状态机逻辑确定性一致所以最终得到的 KV 数据也一致Node Auser:1 → 张三 Node Buser:1 → 张三 Node Cuser:1 → 张三这叫做状态机复制 Replicated State Machine六、读取数据如何处理写请求通常必须发送给 Leader但读请求有多种处理方式。1. 从 Leader 读取最简单的方式GET → Leader这样可以保证读取到最新提交的数据。但 Leader 需要确认自己仍然是当前 Leader否则可能出现旧 Leader 读取旧数据的问题。2. ReadIndexLeader 通过一次心跳确认自己仍然获得多数派支持然后执行读取。适合需要线性一致性的读取。3. Leader LeaseLeader 在一个租约时间内认为自己仍然有效可以直接读取。优点是延迟低缺点是依赖时钟和网络延迟假设使用时需要谨慎。4. 从 Follower 读取可以直接从 Follower 读取但可能读到旧数据客户端写入成功 立即从 Follower 读取 Follower 还没同步完成 返回旧值这种方式称为Stale Read陈旧读取适合对实时一致性要求不高的场景。七、Raft 日志不能无限增长如果所有历史操作永久保存在日志中日志会越来越大PUT a 1 PUT a 2 PUT a 3 PUT b 4 DELETE c ...因此需要快照机制。1. 创建快照当日志达到一定大小时节点将当前状态机状态保存成快照Snapshot a → 3 b → 4然后删除快照之前的旧日志旧日志1 2 3 4 5 6 7 8 9 快照包含1 到 7 保留日志8 92. 新节点加入如果新节点落后太多Leader 不必发送几百万条日志而是直接发送快照Leader ──InstallSnapshot── 新节点新节点恢复快照后再同步快照之后的少量日志。3. 快照和日志的关系可以理解为快照 某个时间点的完整状态 日志 从这个时间点之后的增量操作恢复数据时加载快照 ↓ 重放快照之后的日志 ↓ 得到最新状态八、Raft 如何实现水平扩展一个 Raft 集群通常不应该把全部数据放进一个无限增长的 Raft 日志组否则所有写入都要经过同一个 Leader吞吐量会受限制。更常见的方式是多个 Raft Group例如按照 Key 分片Raft Group 1user:0 ~ user:999 Raft Group 2user:1000 ~ user:1999 Raft Group 3order:0 ~ order:999每个 Raft Group 有自己的 Leader 和副本Group 1A、B、C Group 2D、E、F Group 3G、H、I请求路由层根据 Key 找到对应的 Groupuser:1001 → Group 2 → Group 2 的 Leader这样多个 Group 可以并行处理请求要注意Raft 负责副本一致性 分片负责容量和吞吐扩展 路由层负责把请求送到正确的 Raft GroupRaft 本身并不自动解决数据分片九、一个完整流程图客户端 │ │ PUT user:1001 张三 ▼ 路由层 │ │ 根据 Key 找到 Raft Group ▼ Group Leader │ ├── 追加日志到本地 WAL │ ├── AppendEntries → Follower 1 │ ├── AppendEntries → Follower 2 │ ├── 获得多数派确认 │ ├── 更新 commitIndex │ ├── 应用到本地 KV 状态机 │ ├── 通知 Followers 提交 │ └── 返回客户端成功
延伸阅读

更多相关文章

2026/9/13 1:46:10

基于YOLOv10的蔬果新鲜度检测系统开发实践

1. 项目概述这个项目实现了一个基于YOLOv10目标检测模型的蔬菜水果新鲜度检测系统。作为一个计算机视觉领域的实用项目,它能够通过图像分析技术自动判断蔬果的新鲜程度,支持单张图片、视频文件以及摄像头实时画面三种输入方式。整套系统采用PyTorch框架开…

2026/9/12 22:02:40

鸿蒙应用集成Unreal Engine:高性能3D渲染与跨平台开发实践

1. 项目概述:当鸿蒙遇见Unreal Engine最近在捣鼓鸿蒙应用开发,发现一个挺有意思的方向:把Unreal Engine(UE)集成进来。这可不是简单的“把游戏引擎塞进手机系统”,而是一个关于如何将顶级的实时3D渲染与交互…

2026/9/14 18:35:20

YOLOv11与旋转检测在遥感图像识别中的优化实践

1. 项目背景与核心价值遥感图像识别技术正在经历从传统方法向深度学习的范式转移。去年参与某省自然资源调查项目时,我们团队发现传统遥感解译方法在复杂场景下的平均准确率不足65%,而人工复核需要消耗70%的项目时间。正是在这种背景下,我们决…

2026/9/15 14:42:42

云原生开发环境实战:VS Code/Cursor连接与避坑指南

腾讯云的 CNB 云原生开发环境我实测了差不多两周,最大的感受就一句话:把本地 VS Code、Cursor 那套使用习惯,原封不动搬到浏览器里,而且环境不会因为换电脑就“散架”。这篇内容我会直接围绕“云原生开发环境到底怎么用”&#xf…

2026/9/15 14:42:42

ARIMAX多变量时间序列预测实战:数据预处理到滚动回测

简介:基于ARIMAX的多变量预测模型Python源码与配套数据集,面向统计学、数据科学及相关工科专业的毕业设计、课程设计和期末大作业场景,适合需要快速上手多变量时序预测项目、又担心代码无法运行的学习者。资源包共8个文件,包含2个…

2026/9/15 14:42:42

Spring Boot Actuator heapdump:堆转储泄露敏感信息的原理与防护

前阵子帮一家公司做内部安全自查,翻一个Spring Boot服务时,手滑访问了下/actuator/heapdump,结果浏览器直接给我弹了个大文件下载——几秒钟后我手里多了一个几百兆的.hprof堆转储文件。那会儿我就清楚,这台机器的核心敏感信息基本…

2026/9/15 14:42:42

DINOv3视觉基础模型快速集成实战

DINOv3视觉基础模型快速集成实战 【免费下载链接】dinov3 Reference PyTorch implementation and models for DINOv3 项目地址: https://gitcode.com/GitHub_Trending/di/dinov3 DINOv3 是 Meta AI 推出的自监督视觉基础模型家族,官方 PyTorch 实现与预训练权…

2026/9/15 14:42:42

国产加密芯片大文件上传优化实践与WebUploader改造

1. 项目背景与核心挑战在国产化替代浪潮下,加密芯片正逐步应用于各类信息安全敏感场景。我们团队近期在政务云项目中遇到了一个棘手问题:需要基于百度WebUploader前端组件,实现对国产加密芯片处理的大文件(通常超过10GB&#xff0…

2026/9/15 14:37:41

FastapiAdmin日志体系与核心配置参数深度拆解

搞后端最烦的一件事,就是日志体系没搭好。尤其是 FastapiAdmin 这种集成了 FastAPI SQLAlchemy Pydantic 的框架,运行时涉及请求处理、ORM 查询、任务调度、权限校验好几层,一旦出了问题,日志里如果只有一堆堆栈、没有上下文&am…

2026/9/15 4:54:30

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/15 0:01:16

AI英语单词APP开发:自适应学习算法与移动端优化实践

1. 项目概述 作为一名在移动应用开发领域摸爬滚打多年的老手,我最近完成了一个AI英语单词APP的开发项目。这个项目将传统单词记忆方法与现代AI技术相结合,打造了一款能够智能适应不同用户学习习惯的英语学习工具。 市面上大多数单词APP都存在一个通病&a…

2026/9/15 0:01:16

Flutter与OpenHarmony结合开发手语学习APP实战

1. 项目背景与核心价值作为一名同时接触过Flutter和OpenHarmony的开发者,最近我完成了一个基于Flutter for OpenHarmony的手语学习APP实战项目。这个项目最大的特点在于实现了跨平台框架与国产操作系统深度结合的创新实践——用Flutter开发的应用能完美运行在OpenHa…

2026/9/15 0:01:16

六个月成为机器人工程师:从ROS2到SLAM的实战路径

1. 六个月的紧迫感从哪来:先搞清楚你要成为哪种机器人工程师说实话,六个月的期限并不是一个宽松的时间线。市面上任何一本正经的机器人学教材都超过五百页,ROS2的官方文档可以翻到你怀疑人生,再加上ABB、KUKA这些工业机器人厂家动…

2026/9/15 14:22:53

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/14 13:53:59

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/15 11:42:23

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码