从零开始设计一个分布式KV存储:基于Raft的协程化实现

本文将以一个最小可运行的分布式KV系统为例,带你拆解如何用C++、Raft算法和协程模型构建高可用的Key-Value存储。

一、为什么需要分布式KV?

单机KV(如Redis)存在单点故障容量瓶颈。分布式KV通过多副本+共识算法解决:

  • 高可用:半数节点存活即可服务
  • 强一致:Raft保证所有节点数据一致
  • 水平扩展:分片后可支持海量数据

二、整体架构:协程化的四层设计

我们的系统采用协程化架构(对比线程模型节省90%上下文切换开销):

层级职责关键文件
客户端发起Get/Put请求用户代码
KV服务处理客户端请求,对接RaftkvServer.cpp
Raft核心日志复制、选举、状态机应用raft.cpp
RPC层节点间通信(基于协程的MPRPC)mprpcchannel.cpp
协程调度管理所有网络IO和计算任务fiber.cpp

核心交互流程

ClientKVServerRaftStateMachinePut("x", "1")Propose日志条目日志复制到多数节点日志已提交应用Put操作返回成功ClientKVServerRaftStateMachine

三、Raft算法实现要点

1. 选举机制(解决脑裂问题)

// raft.cpp 选举触发条件
void doElection() {if (m_status != Follower) return;// 随机超时避免选票瓜分m_currentTerm++;convertToCandidate();// 并行向所有节点拉票for (peer : m_peers) {fiber([peer]{RequestVote(peer);});}
}

调试技巧:在doElection()打断点,观察m_currentTermvoteCount

2. 日志复制(保证一致性)

// AppendEntries RPC处理逻辑
bool AppendEntries1(...) {// 关键检查:日志连续性if (prevLogIndex > 0 && log[prevLogIndex].term != prevLogTerm) {return false; // 日志不匹配}// 追加新日志log.erase(log.begin()+prevLogIndex+1, log.end());log.insert(...); 
}

常见错误:日志不一致会导致节点反复拒绝,需检查prevLogIndex/Term

3. 状态机应用(最终可见性)

// kvServer.cpp 应用Raft日志到KV状态机
void GetCommandFromRaft() {while (lastApplied < commitIndex) {lastApplied++;auto cmd = log[lastApplied].command;// 协程安全地操作跳跃表fiber_mutex.lock();ExecuteOpOnKVDB(cmd);fiber_mutex.unlock();// 通知等待的客户端applyCond.notify(cmd.id);}
}

四、协程化网络层设计

为什么选择协程?

  • 传统方案:每个RPC一个线程 → 1000连接=1000线程(内存爆炸)
  • 协程方案:单线程可处理10万协程(通过epoll+用户态调度)

关键实现

// fiber.cpp 协程切换核心
void resume(Fiber* fiber) {// 保存当前上下文到调度器swapcontext(&m_scheduler, &fiber->ctx);
}// 网络IO的协程化改造
void MprpcChannel::CallMethod(...) {// 非阻塞IO,但看起来是同步的int fd = connect(...);fiber_yield(); // 等待可写write(fd, request);fiber_yield(); // 等待可读read(fd, response);
}

五、存储引擎:跳跃表的妙用

KV状态机使用跳跃表而非哈希表:

  • 有序性:支持范围查询(未来扩展)
  • 并发友好:无锁读/细粒度锁写
  • 内存高效:O(log n)时间复杂度
// 插入操作示例
void ExecutePutOpOnKVDB(const PutArgs& args) {m_skipList.insert_or_assign(args.key, args.value);
}

六、调试指南:从日志看系统状态

1. 选举追踪

# 开启调试输出
export RAFT_DEBUG=1# 典型日志
[DEBUG] Node 1 timeout, start election (term=5)
[DEBUG] Node 1 receive vote from Node 2
[DEBUG] Node 1 become Leader in term 5

2. 一致性检查

# 查看所有节点日志一致性
for node in 1 2 3; doecho "=== Node $node ==="curl localhost:800$node/debug/log
done

3. 性能分析

# 协程调度统计
curl localhost:8001/debug/fiber | jq '.'

七、如何扩展这个系统?

  1. 分片:增加ShardMaster模块,按Key范围分片
  2. 压缩:定期快照(参考Raft论文的Snapshot机制)
  3. 成员变更:实现Joint Consensus动态增删节点
  4. 客户端缓存:跟踪Leader ID避免每次请求重定向

八、总结

通过本文,我们构建了一个教学级的分布式KV系统。关键收获:

  • Raft的核心:选举+日志复制+状态机应用
  • 协程的威力:单线程支撑高并发RPC
  • 调试技巧:日志+调试接口快速定位问题

Reference

https://github.com/youngyangyang04/KVstorageBaseRaft-cpp

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/92194.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/92194.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/92194.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

虚拟机或docker的ubuntu无界面安装完成后镜像源设置

ubuntu系统源 在装好虚拟机或者docker镜像后&#xff0c;直接使用apt update && apt upgrade是无法完更新的。 此时系统中也没有vim工具&#xff0c;我们可以在清华源的网站中找到帮助文档。mirrors.tuna.tsinghua.edu.cn/help/ubuntu/为了避免冲突&#xff0c;我们使用…

串口通信02 温度传感DS18B20 01 day49

九&#xff1a;串口通信 通信&#xff1a;无线和有线 ​ 单工 半双工 全双工 并行&#xff1a;多个数据线 串行&#xff1a;一根数据线 同步&#xff1a;通信双方使用同一个时钟&#xff0c;SPI信息帧&#xff0c;有CLK引脚 异步&#xff1a;通信双方使用不同时钟&#xff0c;双…

【FreeRTOS 】任务通知

FreeRTOS 任务通知任务通知简介一 、发送通知1.1 xTaskNotify()1.2 xTaskNotifyFromISR()1.3 xTaskNotifyGive()1.4 xTaskNotifyAndQuery()1.5 xTaskNotifyAndQueryFromISR()二、接收通知2.1 ulTaskNotifyTake()2.2 xTaskNotifyWait()三、清除通知状态和值3.1 xTaskNotifyState…

Android视图状态以及重绘

一、视图状态&#xff08;View States&#xff09;1. 五种核心状态状态作用修改方法特点enabled视图是否响应交互setEnabled(boolean)禁用状态下不响应onTouch事件focused视图是否获得焦点requestFocus()需同时满足focusable和focusableInTouchModewindow_focused视图所在窗口是…

vue3接收SSE流数据进行实时渲染日志

后端使用的是 Spring Boot WebFlux&#xff08;响应式编程框架&#xff09;&#xff0c;并且返回的是 Server-Sent Events (SSE) 流式数据&#xff0c;那么在 Vue3 中&#xff0c;需要使用 EventSource API 或 fetch 流式读取 来正确获取响应内容。方案 1&#xff1a;使用 Eve…

每日五个pyecharts可视化图表-bars(6)

探索pyecharts库中条形图的高级用法与定制技巧 在数据可视化中&#xff0c;条形图是最常用的图表类型之一&#xff0c;它能够清晰地展示不同类别之间的数量对比。今天&#xff0c;我们将继续学习如何使用pyecharts创建5种不同风格的条形图。pyecahts源码 图表1&#xff1a;带…

【C语言】文件操作全解析

文章目录一、为什么需要文件操作&#xff1f;二、认识文件&#xff1a;不止是磁盘上的存储2.1 程序文件2.2 数据文件2.3 文件名的构成三、文本文件与二进制文件&#xff1a;数据的两种形态3.1 存储方式差异3.2 实例对比&#xff1a;整数10000的存储3.3 二进制文件操作示例四、文…

C结构体的几种定义形式 + typedef结合使用的好处

struct 语句定义了一个包含多个成员的新的数据类型&#xff0c;struct 语句的格式如下&#xff1a; struct tag { member-list member-list member-list ... } variable-…

SPICE电容矩阵

SPICE电容矩阵: 如果有许多条传输线,就可以用下标来标记每一条线。例如,如果有5条线,就用1~5分别标记,依惯例把返回路径导体标记为导线0。图10.6给出了5条导线和一个公共返回平面的横截面图。首先研究电容器元件,下一节再讨论电感器元件。 在这个线的集合中,每对导线之间…

【Java】栈和队列

文章目录1.栈1.1 栈的定义1.2 栈的使用1.3 栈的模拟实现2.队列2.1 队列的定义2.2 队列的使用2.3 队列的模拟实现3.循环队列3.1 循环队列的概念3.2 循环队列判断空和满4.双端队列Deque1.栈 1.1 栈的定义 栈是一种特殊的线性表&#xff0c;其只允许在固定的一段进行数据的插入或…

【性能测试】---测试工具篇(jmeter)

目录 1、安装并启动jemeter 2、重点组件 2.1、线程组&#xff1a; 2.2、HTTP取样器​编辑 2.3、查看结果树 2.4、HTTP请求默认值 2.5、HTTP信息头管理器 2.6、JSON提取器 2.7、JSON断言 2.8、同步定时器 2.9、CSV数据文件设置 2.10、HTTP Cookie管理器 3、测试报告…

机器学习(12):拉索回归Lasso

- 拉索回归可以将一些权重压缩到零&#xff0c;从而实现特征选择。这意味着模型最终可能只包含一部分特征。 - 适用于特征数量远大于样本数量的情况&#xff0c;或者当特征间存在相关性时&#xff0c;可以从中选择最相关的特征。 - 拉索回归产生的模型可能更简单&#xff0c;因…

Redis持久化存储

Redis持久化存储详解 一、核心持久化机制 Redis提供两种主要持久化方式&#xff1a;RDB&#xff08;快照&#xff09; 和 AOF&#xff08;追加文件&#xff09;&#xff0c;以及两者的混合模式。 RDB&#xff08;Redis Database&#xff09;快照持久化 工作原理 RDB通过创建数据…

python学智能算法(三十四)|SVM-KKT条件回顾

【1】引言 前序学习进程中&#xff0c;对软边界拉格朗日方程进行了初步构建。 其中约定了两个拉格朗日乘子要非负&#xff0c;其本质是要满足KKT条件。 今天就乘此次机会&#xff0c;在回顾一下KKT条件。 【2】定义 当问题无约束的时候&#xff0c;只要让函数梯度为零&#…

【网络基础】计算机网络发展背景及传输数据过程介绍

本文旨在帮助初学者建立起计算机网络的基础认知&#xff0c;从网络的发展背景到网络协议的分层模型&#xff0c;再到IP与MAC地址的基本概念&#xff0c;全面覆盖第一阶段学习重点。 &#x1f4cc; 本节重点 了解计算机网络的发展背景&#xff0c;掌握局域网&#xff08;LAN&am…

阿里云-通义灵码:解锁云原生智能开发新能力,让云开发更“灵”~

免责声明&#xff1a;此篇文章所有内容皆是本人实验&#xff0c;并非广告推广&#xff0c;并非抄袭&#xff0c;如有侵权&#xff0c;请联系笔者。 每日一句 信念其实就是相信未来&#xff0c; 相信内在&#xff0c; 以及坦然美好的心境。 目录 每日一句 一. 引言 二.通义…

lesson33:Python协程详解:从原理到实战的异步编程指南

目录 一、协程核心概念&#xff1a;轻量级并发的本质 1.1 什么是协程&#xff1f; 1.2 协程与线程/进程的对比 二、协程工作原理&#xff1a;事件循环与协作式调度 2.1 事件循环&#xff08;Event Loop&#xff09;&#xff1a;协程的"调度中心" 2.2 协作式调度…

深入理解C++模板进阶:非类型参数、特化与分离编译

前言C模板是泛型编程的核心&#xff0c;它允许我们编写与类型无关的代码。在掌握了模板的基础知识后&#xff0c;我们需要进一步了解模板的高级特性&#xff0c;以便更灵活地使用它们。本文将深入探讨三个重要的模板进阶主题&#xff1a;非类型模板参数、模板特化以及模板的分离…

使用winsw把SpringBoot项目注册成window服务

目录 一、使用winsw注册 1.1、项目打jar包 1.2、下载winsw 1.3、把 WinSW.NET4.exe 重新命名 1.4、编写m配置文件用于配置注册信息 1.5、创建文件夹存放你的文件 1.6、安装服务 1.7、启动服务 1.8、卸载服务 1.8、停止服务 一、使用winsw注册 1.1、项目打jar包 例如项目jar包名…

进阶向:Python开发简易QQ聊天机器人

数字化时代的聊天机器人应用在当今数字化时代&#xff0c;聊天机器人已经成为日常生活和商业活动中不可或缺的一部分。根据市场研究数据显示&#xff0c;全球聊天机器人市场规模预计将在2026年达到102亿美元&#xff0c;年复合增长率达到34.75%。这些智能助手正广泛应用于以下场…