基于raft的kvDB

1 raft共识算法

raft是强leader模型,通过选举leader来实现一致性leader拥有完全的能力来管理复制日志。leader从客户端获取日志条目,复制到其他的服务器中,告诉他们什么时候应用这个日志到状态机是安全的。

leader这个角色简化了复制日志的管理。leader可以在不咨询其他服务器的前提下添加新的日志条目,数据只从leader流向其他服务器

如果一个leader宕机或者失联了,一个新的leader就会被选举。

Raft把一致性问题分解为三个独立的部分:

  • leader选举。当现有的leader失败后,新的leader必须被选举产生。
  • 日志复制。leader必须接收客户端的日志条目然后通过集群复制,强制其他服务器的日志和leader的一样。
  • 安全性。如果一个服务器应用了一条日志,那么其他的服务器应用的相同条目的日志内容就是一样的。  这样的话,follower已经应用的日志和leader相同,follower的snapshot也不会和leader冲突。

2 State

2.1 所有节点都维护的需要持久化的状态

int m_me;                                     // raft节点的标识
int m_currentTerm;                            // 当前trem(任期)
int m_votedFor;                               // 记录当前任期给谁投了票
std::vector<raftRpcProctoc::LogEntry> m_logs; // 日志条目数组(日志:index,term,指令)

2.2 所有节点都维护的易失性状态

都初始化为0

int m_commitIndex; // 已经被提交的最新的log的index
int m_lastApplied; // 已经应用给状态机(kvsrver)的最新的log的index

2.3 只有leader需要维护的易失状态

// 对于每一个节点,leader(当前节点)下次应该从哪个日志开始发送;初始化未leader的log的最大index+1
std::vector<int> m_nextIndex;  
// 对于每一个节点,在哪个日志和leader(当前节点)匹配;初始化为0
std::vector<int> m_matchIndex; 

3 服务器规则

3.1 所有的服务器

  • 如果commitIndex>lastApplied:增加lastApplied,应用log[lastApplied]到状态机
  • 如果RPC的请求或者回复中的term T>currentTerm:设置currentTerm=T,转为follower

3.2 Follower

  • 回复来自candidate和leader的RPC
  • 如果经过了选举超时(election timeout)还没有收到当前leader的AppendEntries或者candidate的投票请求:转为candidate

3.3 candidate

  • 转为candidate之后,开始选举
    • 给所有的服务器发送RequestVote RPC
    • 重设选举定时器
    • 为自己投票
    • 增加currentTerm
  • 如果收到大多数服务器的选票:成为leader
  • 如果收到新leader的AppendEntries RPC转为follower
  • 如果经过了选举超时(选举定时器到达了):开始一个新的选举

3.4 leader

  • 定时发送空的AppendEntries RPC(心跳)给所有的服务器
  • 如果收到了客户端指令:将新的条目添加到本地日志中,在应用到状态机之后返回结果。当前项目中kvserver负责与客户端通信。
  • 如果最大的日志索引>=follower的nextIndex:发送从包含nextIndex开始的日志条目的AppendEntries RPC:
    • 如果因为日志的不一致导致失败:leader减小nextIndex然后重试
    • 如果成功:更新follower的nextIndex和matchIndex
  • 如果存在一个N,N>commitIndex,大部分的matchIndex[i]>=N。而且log[N].term==currentTerm,设置commitIndex=N。(只有当前term有日志提交,才更新commitIndex)

4 安全性

论文:

选举安全:在给定的期限内,最多只能选举一位leader。§5.2

只能leader添加日志:leader永远不会覆盖或删除其日志中的条目; §5.3

日志匹配:如果两个日志包含具有相同索引和任期的条目,则在给定索引之前的所有条目的内容都是相同的。§5.3

leader完整性:如果某一任期内一条日志被提交,则该条目将出现在之后任期leader中。§5.4

leader提交了某一条日志,说明该日志被复制到大多说节点。然后leader宕机,其它节点发起选举。没有复制这条日志的节点的log比大多数节点旧,所以不可能获得大多数选票,不能成为leader .只有复制了上一任leader提交的最新的日志的节点才能成分下一任leader.

状态机安全性:如果服务器已在其状态机应用给定索引日志条目,则其他任何服务器都不会在该索引处应用其他内容的日志条目 §5.4.3

5 选举

leader向所有follower定时发送心跳信号(不携带日志条目的AE RPC),以维护其领导地位。只要服务器收到来自leader或者candidate有效RPC,就会保持follower状态。如果follower在称为选举超时(election timeout)的时间段内没有任何通信,则它假定没有可行的leader,并开始竞选新leader。

5.1 开始选举

转为candidate之后,开始选举

  • 给所有的服务器发送RequestVote RPC
  • 重设选举定时器
  • 为自己投票
  • 增加currentTerm

5.2 选举结果

一个candidate继续保持它的状态直到有以下一种情况发生:

  1. 它赢得了选举
  2. 另一个服务器成为了leader
  3. 没有leader产生

5.2.1 赢得了选举

在一个任期内(一次选举过程,也是一个term),如果收到大多数服务器投票,candidate就赢得了选举。

每个服务器在一个任期中最多给一个candidate投票,而且是基于先来先服务原则(限制:投票要求candidate的日志不比自己旧)。

这个大多数规则保证了最多一个candidate可以赢得某一任期的选举(选举安全性)。

一旦一个candidate赢得了选举,它就成为了leader。它给集群中所有的服务器发送心跳以建立它的地位,同时也阻止了新的选举发生

5.2.2 另一个服务器成为了leader

当等待投票的时候,candidate可能收到另一个服务器声明已经成为leader的AppendEntries RPC。

如果这个leader的任期不低于这个candidate的任期,这个candidate就承认leader的正当性然后成为follower。

如果这个RPC中的任期比candidate的任期小,这个candidate就就拒绝这个RPC,然后继续保持candidate状态。(可能是旧的leader重连)

5.2.3 没有leader产生

没有candidate赢得或者输掉这个选举。原因就是多个follower同时成为candidate,投票会分散给各个candidate,从而没有candidate获得了大多数的票。

当这种情况发生,每个candidate会等到超时然后增加它的任期号开始新一轮的选举。然而,没有额外的措施的话,分裂投票的情况还会出现。

Raft使用随机的选举超时(randomized election timeout)来解决分裂投票。选举超时在一定的范围(150-300ms)内随机获得。这会把所有的服务器分散开来,因此在大多数情况下,只有一个服务器会经历完选举超时。 它在其他服务器到达选举超时之前赢得选举和发送心跳。 每个candidate在选举开始时都会重置选举定时器,并等待该定时结束后再开始下一次选举。

5.3 选举流程

5.3.1 electionTimeOutTicker

负责查看是否该发起选举,如果该发起选举就执行doElection发起选举。

5.3.2 doElection

改变状态为candidate,发起选举,构造需要发送的rpc对象,调用sendRequestVote发送rpc并处理rpc响应结果。发送给所有节点,每个节点对应一个线程

当前节点状态变化:

m_status = Candidate;
m_currentTerm += 1;
m_votedFor = m_me;          // 自己给自己投,也避免candidate给同辈的candidate投

tips:

  • 发起选举后,会重置选举定时器。如果选举定时器超时就必须重新选举,不然没有选票就会一直卡住;
  • 重竞选超时导致重新选举,term也会增加

5.3.3 sendRequestVote

负责发送选举中的RPC,在发送完rpc后还需要负责接收并处理对端发送回来的响应。

5.3.4 RequestVote

接收别人发来的选举请求,主要检验是否要给对方投票。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/446393.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

实现“ 字体逐渐展现 ”程序

本期介绍&#x1f356; 主要介绍&#xff1a;如何实现在屏幕上从两边向中间逐渐打印字符串。 题目&#xff1a;编写字体逐渐展现程序&#xff0c;功能是&#xff1a;多个字符从两端向中逐渐间显现&#xff0c;直到全部显示为止。举个例子&#xff0c;要逐渐显示“hello world ”…

MEMTO: Memory-guided Transformer for Multivariate Time Series Anomaly Detection

目录 一、问题与思路1.1 现存问题1.2 解决思路 二、模型与方法2.1 模型概览2.2 Encoder and decoder2.3 门控存储器模块2.3.1 门控存储器更新阶段2.3.2 查询更新阶段2.3.3 损失函数2.3.4 初始化内存项2.3.5 异常评分2.3.6 阈值设定 三、实验与分析3.1 模型结果3.2 消融实验3.3 …

宝塔一键迁移报错创建失败问题完美解决

很多站长朋友在使用宝塔面板迁移的时候总是出错&#xff0c;如图&#xff1a; 遇到这样的问题不要慌&#xff0c;我们已经完美处理&#xff0c;详细解决教程&#xff1a;宝塔一键迁移报错问题完美解决教程

深入理解操作系统Operator System(2)

目录 操作系统对上的管理 系统调用接口 用户操作接口&#xff08;库函数&#xff09; 系统调用和库函数的概念 结构层次示意图 总结 为什么要有操作系统❓ 上次主要介绍了操作系统的"管理"和操作系统对下的管理。本篇主要是对上的管理。 操作系统对上的管理 …

Linux智能网关结合Node-RED实现实时工业数据采集

工业4.0的发展&#xff0c;物联网技术在制造业中的应用越来越广泛。其中&#xff0c;基于Linux系统的工业物联网智能网关因其开放性、稳定性和安全性而备受青睐。这类智能网关创新性地集成了开源工具Node-RED&#xff0c;为从各种工业设备&#xff08;如PLC&#xff09;中高效收…

安装torch以及版本对应问题

首先查看cuda版本&#xff1a;winR 输入&#xff1a;nvidia -smi 我的cuda版本12.2&#xff0c;安装的torch版本要小于12.2 我的pip/conda源都改成清华源了&#xff0c;torch2.0以上的版本截止到2024年3月10日也没有。 pytorch官网&#xff1a;https://pytorch.org/ 寻找匹配…

关于比特币的AI对话

【ChatGPT】 比特币源码开源吗&#xff1f; 是的&#xff0c;比特币的源码是开源的。比特币项目是在MIT许可证下发布的&#xff0c;这意味着任何人都可以查看、修改、贡献和分发代码。比特币的源码托管在GitHub上&#xff0c;可以通过下面的链接进行访问&#xff1a; https://g…

注意!!墙裂推荐几个好用的实用小工具!一定会用到的!

前言 在开发的世界里&#xff0c;面对各种挑战和问题时&#xff0c;拥有一套合适的工具箱至关重要。这不仅能提升我们的工作效率&#xff0c;还能让复杂的任务变得简单&#xff0c;甚至在解决棘手问题的同时&#xff0c;还能让我们的心情略微舒畅。众所周知&#xff0c;有用的…

【EtherCAT实践篇】九、EtherCAT增加变量示例:增加浮点数输入变量

目的&#xff1a;在EtherCAT开发板上IO程序基础上进行修改&#xff0c;将原来的16位整数型数据Analog input改为32位浮点数&#xff0c;基于STM32F405底板。 1、XML配置修改 1.1 更改数据类型 ETG1020基础数据中包括浮点数 REAL&#xff0c;可以直接使用浮点数。 这里在xml…

MySQL索引+常见问题详解

网络上的讲述MySQL索引的文章太多了&#xff0c;我打算换个角度来说。我们尝试着从设计者的角度思考&#xff0c;索引为什么这么设计。 假如你是索引的设计者&#xff0c;你会如何设计索引。我们不妨以新华字典为例。如果我们要查询汉字爱是什么意思&#xff0c;我们有如下操作…

【读书笔记】针对ICS的ATTCK矩阵详解(一)

Techniques - ICS | MITRE ATT&CKhttps://attack.mitre.org/techniques/ics/ 一、初始访问&#xff08;Initial Access&#xff09; 该阶段&#xff1a;攻击者正在尝试进入ICS环境。 初始访问包括攻击者可能用作入口向量&#xff0c;从而可以在 ICS 环境中获得初始立足点的…

怎么在学习强国网上发布文章,学习强国投稿发稿方法途径,附学习强国多少钱价格明细表

学习强国是一款受用户欢迎的学习软件&#xff0c;许多人希望在其平台上发布自己的文章&#xff0c;以分享和传播自己的学习成果和心得体会。那么&#xff0c;怎么在学习强国网上发布文章呢&#xff1f;接下来&#xff0c;我们将介绍一些投稿发稿的方法和途径。 首先&#xff0c…

PLC的FC与FB模块程序的功能解析

前文讲了在西门子系列的PLC中四个程序模块的描述&#xff0c;从S7-1200PLC开始就有FC和FB程序块了&#xff0c;但在使用的时候&#xff0c;一些使用者还是不好理解&#xff0c;以至于不知道该如何选择。今天&#xff0c;我们就用大白话的方式给大家讲解FC与FB的功能。 1、FC与…

Python打印Linux系统中最常用的linux命令之示例

一、Linux中的~/.bash_history文件说明&#xff1a; 该文件保存了linux系统中运行过的命令的历史。使用该文件来获取命令的列表&#xff0c;并统计命令的执行次数。统计时&#xff0c;只统计命令的名称&#xff0c;以不同参数调用相同的命令也视为同一命令。 二、示例代码&am…

数据结构二叉树续

在前边我们讲完了二叉树的一些代码结构 现在呢我们需要进一步去细化 我们传参数组后&#xff0c;让数组里面的数据进行调整 如何调整成堆呢&#xff1f; 建堆 所以我们分装一个成堆的函数 还是先去断言 然后创建空间 这里我们需要用到一个memcpy函数 memcpy函数是用来…

RabbitMQ - 07 - 通过注解创建队列和交换机

之前消息模型的实现,都是通过rabbitMQ Management 控制台来手动创建 queue 和 exchange 的 在项目开发中有两种方式通过代码声明 创建 一种是通过 Bean 方式,这种代码量较大 稍繁琐 一种是通过注解的方式声明 先编写消费者代码 通过注解绑定了 消息队列,交换机,还有 routin…

预约自习室

预约自习室 1、技术介绍 自习室预约系统的后端开发语言采用Node&#xff0c;后端开发框架采用Express&#xff0c;数据库采用的Node的最佳搭档MySQL。采用Vue作为前端开发框架&#xff0c;Element-UI作为开发的组件库&#xff0c;微信小程序。期间采用axios实现网页数据获取&a…

Linux 进程程序替换

&#x1f493;博主CSDN主页:麻辣韭菜-CSDN博客&#x1f493;   ⏩专栏分类&#xff1a;http://t.csdnimg.cn/G90eI⏪   &#x1f69a;代码仓库:Linux: Linux日常代码练习&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Linux知识   &#x1f51d;&#x1f5…

springboot257基于SpringBoot的中山社区医疗综合服务平台

中山社区医疗综合服务平台的设计与实现 摘 要 传统信息的管理大部分依赖于管理人员的手工登记与管理&#xff0c;然而&#xff0c;随着近些年信息技术的迅猛发展&#xff0c;让许多比较老套的信息管理模式进行了更新迭代&#xff0c;居民信息因为其管理内容繁杂&#xff0c;管…

车载诊断协议DoIP系列 —— 传输层控制协议(TCP)用户数据报协议(UDP)

车载诊断协议DoIP系列 —— 传输层控制协议(TCP)&用户数据报协议(UDP) 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师(Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 本就是小人物,输了就是输了,不要在意别人怎…