[分布式一致性协议] ------ raft协议的解释与理解

前言

在分布式系统中,为了保证容错性,一般会维护多个副本集群,提高系统的高可用,但与之带来的问题就是多个副本的一致性(consensus)问题。
我们认为,对于一个具有一致性的的集群中,同一时刻所有节点对存储在其中的值都应该是相同的,并且在集群大部分节点可用时,集群也是可用的。
能完成这种一致性的协议,就叫一致性协议。
常见的分布式一致性协议有:

  • 两阶段提交协议,
  • 三阶段提交协议,
  • 向量时钟,
  • RWN协议,
  • paxos协议,
  • Raft协议等

所以本文说的raft协议,就是一种分布式一致性协议,他定义了易于实现一致性协议的实施标准,可以维护多个副本的一致性。

raft协议中,我们有以下规定:

1.集群中的节点,只有三种角色(leader,follower,candidate)

leader:

领导者,只有leader才能处理客户端请求,同步数据到其他实例。同时负责周期性的发送心跳包(heartbeat)到follower,目的是为了维持自己的leader角色。算法保证任何时刻都只存在一个合法的leader。

follower:

跟随者,被动接收RPC请求并做响应,比如leader请求添加日志数据,candidate请求选举。follower本身是被动的,不会主动发起RPC。

candidate:

候选人,当follower一段时间内没有收到leader的heartbeat(可能是leader挂了,可能是自己网络出问题了),就认为当前leader失效,转变为candidate角色。

2.term:任期,由一个唯一的id标识,每选举一次,term就会自增,leader永远是有最新的term。每个term一开始就会先进行选举:

3.LogEntry:客户端的一个命令对应一个LogEntry

raft协议中有两个重点(选举leader和日志复制):

1.Leader election(选举leader)

  1. follower将自己维护的current_term_id加1。
  2. 然后follower将自己的状态转成candidate(候选人)。
  3. 发送拉票消息给其它所有server
  4. 如果收到其他leader的消息,则证明有leader了;如果收到大部分的投票,就变成leader,同时通知其他人;否则重复123步骤

在这里插入图片描述
在上图这个选举的过程中,对于某个候选人,会有以下三种情况:

1.自己成为leader

获取相同term下超过半数的投票。

2.别人成为leader

candidate在等待投票的过程中,可能收到其他实例的AppendEntries RPCs,
如果发现RPC里参数的term >= 自身的currentTerm,那么就意识到已经有新的leader选出,自己败选,转为follower.
如果收到其他实例的RequestVote RPCs,发现RPC里的参数term > 自身的currentTerm,那么就意识到已经有新的term开始,转为follower.

3.没有选出leader

当投票被瓜分,没有任何一个candidate收到了majority的vote时,没有leader被选出。
这种情况下,每个candidate等待的投票的过程就超时了,接着candidates都会将本地的current_term_id再加1,发起拉票进行新一轮的leader election。

此外,影响成为leader的因素,不止任期,还有日志长度,日志长度的优先级低于任期的优先级。

总结来说,当一个实例收到RequestVote RPC时,要先判断任期是否大于本身,如果是,就直接投票,如果不是,再判断这个rpc的发送者的日志长度是不是小于等于自己,如果不是,就拒绝投票。

举个例子:

有A B C D E 5个实例(1)A当选为leader,同步数据到D E并commit,之后D E宕机(2)此时A网络断连,B C都成为candidate,不断自增term,但由于只有两个实例,无法满足大多数的条件(3)A网络恢复,此时B C term都较高,因此A接收到RequestVote后转为follower(4)A B C 3个实例,如果B C随机超时时间总是较短,那么总是能发出RequestVote RPC使得A转为follower一直无法参与选举(5)由于A的日志里已经有commit的数据,此时规则需要保证A胜出对于刚刚网络恢复的A来说,如果收到B或C的RequestVote RPC,会因为自己的日志长度大于B或C,从而拒绝投票,那么B或C就得不到大多数的投票(5个实例,大多数至少是3票),最终引起选举超时,然后ABC将会重新开始选举,直到A发起投票,成为leader。

再说说上面例子中的选举超时:

	为了尽可能避免平票的问题,同时就算平票,也能快速解决,选举超时的时间是很讲究的,官网给定的是在(150ms~300ms)直接随机取一个超时时间。如此一来,大多数情况下就只有一个节点会发起选举。即使出现平票,每个节点又会在一个随机时间后(重置timer)开始新的选举,避免了重复平票。(注意,这种随机的超时时间,是一种思想,不仅在选举中会用到,我们也要在其他场景中想到这种方案。)

选举超时重置的3种情况:

		(1)candidate开始选举后,要重置timer(2)如果收到RequestVote,只有在投票给对方转为follower的情况下,才重置(3)如果收到AppendEntries,而且收到的term比自身大,则转为follwer并重置

2.Log Replication (日志复制)

在这里插入图片描述
最上面这个是新leader,a~f是follower,每个格子代表一条log entry,格子内的数字代表这个log entry是在哪个term上产生的。
(1)a、b少数据
(2)c、d多数据
(3)e、f数据冲突

为什么leader和follower的日志是一致的:

需要有一种机制来让leader和follower对log达成一致,leader会为每个follower维护一个nextIndex(比如上图的1到12),表示leader给各个follower发送的下一条log entry在log中的index,初始化为leader的最后一条log entry的下一个位置。
leader给follower发送AppendEntriesRPC消息,带着(term_id, (nextIndex-1)), term_id即(nextIndex-1)这个槽位的log entry的term_id,
follower接收到AppendEntriesRPC后,会从自己的log中找是不是存在这样的log entry,如果不存在,就给leader回复拒绝消息,然后leader则将nextIndex减1,再重复,直到AppendEntriesRPC消息被接收。

以leader和b为例:

	初始化,nextIndex为11,leader给b发送AppendEntriesRPC(6,10),b在自己log的10号槽位中没有找到term_id为6的log entry。则给leader回应一个拒绝消息。接着,leader将nextIndex减一,变成10,然后给b发送AppendEntriesRPC(6, 9),b在自己log的9号槽位中同样没有找到term_id为6的log entry。循环下去,直到leader发送了AppendEntriesRPC(4,4),b在自己log的槽位4中找到了term_id为4的log entry,接收了消息。随后,leader就可以从槽位5开始给b推送日志。

最后附上raft协议的原论文和中文翻译

原文:https://ramcloud.atlassian.net/wiki/download/attachments/6586375/raft.pdf
翻译:https://blog.csdn.net/chenhaifeng2016/article/details/54880091 (翻译难免会附加译者的思想,建议最好还是看原文,能感受到原作者的思想)

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

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

相关文章

利用.dSYM和.app文件准确定位Crash位置

当发布到iPhone上的应用程序Crash之后,iPhone会自动生成一个Crash Log(*.crash),这个文件包含了一些有用的调试信息,但对于堆栈,它只记录的函数地址,而无法显示函数名。函数名保存在一个叫dSYM的…

MVPVM模式介绍

一、概述MVPVM即:Model-View-Presenter-ViewModel。此模式是MVVM和MVP模式的结合体。但是交互模式发生了比较大的变化。MVVM参考本博客文章:iOS-MVVM-模式介绍MVP参考本博客文章:MVP模式介绍 二、原理:Presenter同时持有View、Mod…

分组密码的工作模式

一、理论基础1.概述密码学中,块密码的工作模式允许使用同一个块密码密钥对多于一块的数据进行加密,并保证其安全性。块密码自身只能加密长度等于密码块长度的单块数据,若要加密变长数据,则数据必须先被划分为一些单独的密码块。通…

PBOC3.0中使用的国密SM2算法

一、知识准备 PBOC3.0规范就是《中国金融集成电路(IC)卡规范》3.0版本。SM2是国密局推出的一种他们自己说具有自主知识产权的非对称商用密码算法。本身是基于ECC椭圆曲线算法的,所以要讲SM2, 先要弄懂ECC。 完全理解ECC算法需要一定的数学功底…

Markdown入门

Markdown 是一种轻量级的「标记语言」,它的优点很多,目前也被越来越多的写作爱好者,撰稿者广泛使用。看到这里请不要被「标记」、「语言」所迷惑,Markdown 的语法十分简单。常用的标记符号也不超过十个,这种相对于更为…

mysql数据库支持emoji表情的详解

mysql存储emoji表情的时候,就会报错,如下: Error updating database. Cause: java.sql.SQLException: Incorrect string value: ‘\xF0\x9F\x98\x8A\xF0\x9F…’ for column ‘这是我表中的字段’ at row 1 初步定位是我的数据库是utf8编码…

编程规范:长函数的思考

在工作,我们应该都不想看到非常的长函数。对于一个运行5年左右的项目,极有可能出现这种情况。由于长函数的长、if/else嵌套,导致代码的可读性非常差,这对于项目的维护和开发带来了极大的困难。所以我们应该避免写长函数&#xff0…

用redis实现延迟队列

现在在用的redis实现延迟队列的主流程

maven更新快照不起作用的解决方法

问题:maven的快照包更新后,调用方使用idea点下面这个地方更新maven,并没有拉到最新的快照 解决方法1 删除本地仓库的快照包,再重新拉一次 解决方法2 下图,这里点进去 下图,这个勾上就行了,再…

iOS中frame和Bounds之间的区别

frame frame是每个view必备的属性,代表的是当前视图的位置和大小,没有设置他,当前视图是看不到的。位置需要有参照物才能确定,数学中我们用坐标系来确定坐标系中的某个点的位置,iOS中有他特有的坐标系,如下…

[数据库]-----记一次mysql分库的操作(冷热分离)

前提: 1.原有库是mysql数据库,已经根据用户pin分片 2.每片是一主两从 3.主表已经分过表了 4.数据库所在服务器为4C8G 5.库中数据量已经超过千万,而且以每天3万多的数据持续增长,将来每天或许会更多 6.库内数据为订单数据,每时每刻都有新的订单产生,每个…

iOS网络请求认证挑战

一、引言 Http请求中认证挑战相关的代理如下: 1.将要发送一个认证挑战的请求 - connection:willSendRequestForAuthenticationChallenge:2.是否能够对一个保护空间进行认证(已废弃)- connection:canAuthenticateAgainstProtectionSpace:3.…

CDN的实现原理

一、传统模式 在描述CDN的实现原理前,让我们先看传统的未加缓存服务的访问过程,以便了解CDN缓存访问方式与未加缓存访问方式的差别: 用户提交域名→浏览器对域名进行解释→得到目的主机的IP地址→根据IP地址访问发出请求→得到请求数据并回复…

一个简单的权限系统模型

我们知道,一般说的简单的权限系统,都是使用shiro或者spring-security shiro之前用的比较多,原理也容易理解,算是比较成熟的权限方面的框架spring-security相对源码比较难懂,但由于与spring的完美融合,也有…

获取iOS任意线程调用堆栈(一)获取任意线程的调用栈地址列表

转载自:http://blog.csdn.net/jasonblog/article/details/49909163 如果要获取当前线程的调用栈,可以直接使用现有API:[NSThread callStackSymbols]。 但是并没有相关API支持获取任意线程的调用栈,所以只能自己编码实现。 1. 基础…

获取iOS任意线程调用堆栈(二)符号化理论:Mach-o文件结构

我们知道Windows下的文件都是PE文件,同样在OS X和iOS中可执行文件是Mach-o格式的。 所以我们如果要进行逆向分析,首先要熟悉Mach-o文件结构。 Mach-o包含三个基本区域: 头部(header structure)。 加载命令(…

获取iOS任意线程调用堆栈(三)符号化理论:从Mach-o结构分析类名方法名

下面来讲讲如何从Mach-o文件中分析出类名和方法名,也让我们了解下class-dump的原理。 Mach-o结构有两个节:__objc_classname 和 __objc_methname 其中就是类名和方法名。 其中__objc_classname的偏移为:ox7961 __objc_methname的偏移为0x6…

获取iOS任意线程调用堆栈(四)符号化实战

转载自:http://blog.csdn.net/jasonblog/article/details/49909209 1. 相关API和数据结构 由于我们在上面回溯线程调用栈拿到的是一组地址,所以这里进行符号化的输入输出应该分别是地址和符号,接口设计类似如下: - (NSString *)s…

获取iOS任意线程调用堆栈(五)完整实现:BSBacktraceLogger

转载自:https://toutiao.io/posts/aveig6/preview BSBacktraceLogger 是一个轻量级的框架,可以获取任意线程的调用栈,开源在我的 GitHub,建议下载下来结合本文阅读。 我们知道 NSThread 有一个类方法 callstackSymbols 可以获取调…

Mac电脑如何彻底删除清除数据?CleanMyMac X软件更专业

虽然不用杀毒,但是日常的清理还是有必要的,特别是卸载一些软件会有残留,可以用命令mdfind来找,然后删,这里给新手用户推荐一款应用clean my mac x,定期清理一下,不用的时候关掉就可以。 CleanM…