摘取自:  http://mp.weixin.qq.com/s?__biz=MzIyMTQ1NDE0MQ==&mid=2247483979&idx=1&sn=12864382e233fe9b900ab14349404032&chksm=e83dc819df4a410f5959b6922025d317d6c497b7110c4c5d8720fb2b0a70246ce651f9a19e91&mpshare=1&scene=1&srcid=0125HVXp5VF5Kuav7ko8iCrb#rd

0 - Raft协议和Paxos的因缘

读过Raft论文《In Search of an Understandable Consensus Algorithm》的同学都知道,Raft是因为Paxos而产生的。Paxos协议是出了名的难懂,而且不够详细,紧紧依据Paxos这篇论文开发出可用的系统是非常困难的。Raft的作者也说是被Paxos苦虐了无数个回合后,才设计出了Raft协议。作者的目标是设计一个足够详细并且简单易懂的“Paxos协议”,让开发人员可以在很短的时间内开发出一个可用的系统。

 

Raft协议在功能上是完全等同于(Multi)-Paxos协议的。Raft也是一个原子广播协议(原子广播协议参见《由浅入深理解Paxos协议(1)》),它在分布式系统中的功能以及使用方法和Paxos是完全一样的。我们可以用Raft来替代分布式系统中的Paxos协议如下图所示:

1 - Raft的设计理念

严格来说Raft并不属于Paxos的一个变种。Raft协议并不是对Paxos的改进,也没有使用Paxos的基础协议(The Basic Protocol)。Raft协议在设计理念上和Paxos协议是完全相反的。正是由于这个完全不同的理念,使得Raft协议变得简单起来。

Paxos协议中有一个基本的假设前提:可能会同时有多个Leader存在。这里把Paxos协议执行的过程分为以下两个部分:

  • Leader选举

  • 数据广播

在《由浅入深理解Paxos协议(2)》的“Leader的选取”一节中提到过,Paxos协议并没有给出详细的Leader选举机制。Paxos对于Leader的选举没有限制,用户可以自己定义。这是因为Paxos协议设计了一个巧妙的数据广播过程,即Paxos的基本通讯协议(The Basic Protocol)。它有很强的数据一致性保障,即使在多个Leader同时出现时也能够保证广播数据的一致性。

而Raft协议走了完全相反的一个思路:保证不会同时有多个Leader存在。因此Raft协议对Leader的选举做了详细的设计,从而保证不会有多个Leader同时存在。相反,数据广播的过程则变的简单易于理解了。

 

2 - Raft的日志广播过程

为了保证数据被复制到多数的节点上,Raft的广播过程尽管简单仍然要使用多数派协议,只是这个过程要容易理解的多:

  1. 发送日志到所有Followers(Raft中将非Leader节点称为Follower)。

  2. Followers收到日志后,应答收到日志。

  3. 当半数以上的Followers应答后,Leader通知Followers日志广播成功。

- 日志和日志队列

Raft将用户数据称作日志(Log),存储在一个日志队列里。每个节点上都有一份。队列里的每个日志都一个序号,这个序号是连续递增的不能有缺。

日志队列里有一个重要的位置叫做提交日志的位置(Commit Index)。将日志队列里的日志分为了两个部分:

  • 已提交日志:已经复制到超过半数节点的数据。这些日志是可以发送给应用程序去执行的日志。

  • 未提交日志:还未复制到超过半数节点的数据。

当Followers收到日志后,将日志按顺序存储到队列里。但这时Commit Index不会更新,因此这些日志是未提交的日志,不能发送给应用去执行。当Leader收到超过半数的Followers的应答后,会更新自己的Commit Index,并将Commit Index广播到Followers上。这时Followers更新Commit Index,未提交的日志就变成了已提交的日志,可以发送给应用程序去执行了。

从上面的解释我们可以知道,日志队列中已经提交的日志是不可改变的,而未提交的日志则可以被更新成其他的日志(在Leader发生变化时会发生)。

Raft的日志队列和《由浅入深理解Paxos协议(1)》中的“预存储队列+存储队列”功能是一样的,但是巧妙的合并到了一起。这样做解决的问题和《由浅入深理解Paxos协议(1)》中“预存储队列+存储队列”解决的问题也是一样的,这里就不再叙述。

3 - Raft的Leader选举

Raft称它的Leader为“Strong Leader”。Strong Leader 有以下特点:

  • 同一时间只有一个Leader

  • 只能从Leader向Followers发送数据,反之不行。

下面我们看一下Raft通过哪些机制来实现Strong Leader。

 

- 多数派协议

为了保证只有一个Leader被选举出来,选举的过程使用了多数派协议。这样很好理解,当一个Candidate(申请成为Leader的节点)请求成为Leader时,只有半数以上的Followers同意后,才能成为Leader。投票过程如下:

  1. 当发现Leader无响应后(一段时间内没有日志或心跳),Candidate发送投票请求。

  2. Followers投票。

  3. 如果超过半数的Followers投了票,则Candidate自动变成Leader,开始广播日志。

- 随机超时机制

和《由浅入深理解Paxos协议(1)》中提到问题一样,这里也会发生多个Candidate同时发送投票请求,而导致谁都不能够得到多数赞成票的情况,有可能永远也选不出Leader。为了保证Leader选举的效率,Raft在投票选举中使用了随机超时的机制:

  1. 在每个Followers上设定的Leader超时时间是在一个范围内随机的。这样可以尽量让Followers不在同一时间发起Leader选举。

  2. 每个Candidate发起投票后,如果在一段时间内没有任何Candidate称为Leader则,需要重新发起Leader选举。这段等待的时间,在每个Candidate上也是随机的。从而保证不会有多个Candidate同时重新发起Leader选举。

虽说是随机的超时时间,但是也有个范围,太小或者太大都会影响系统的可用性。太小会导致过多的选举冲突,太大又会影响系统的平滑运行。在Raft的论文中,作者将这个超时时间称为electionTimeout,并给出了合理的范围,公式如下:

broadcastTime ≪ electionTimeout ≪ MTBF

“≪”代表数量级上的差异(10倍以上)。

 

- Candidate的日志长度要等于或者超过半数节点才能选为Leader

当Leader故障时,Followers上日志的状态很可能是不一致的有的多有的少而且Commit Index也不尽相同。

我们知道已经提交的日志是不能够丢弃的,必须要最终复制到所有的节点上才行。假如在选Leader时,图中Candidate A变成了Leader,就必须要首先从Candidate B上将日志4复制过来,然后才能开始处理新的日志。为了减少复杂性,raft就规定,只有包含了所有已提交日志的Candidate才能当选为Leader。

实现也很简单:

  • 当发现Leader无响应后(一段时间内没有数据或心跳),Candidate发送投票请求,请求中包含自己日志队列的长度(或者说最大日志的Index)

  • Followers检查Candidate的日志长度,只有Candidate的日志等于或者长于自己才投票。

  • 如果超过半数的Followers投了票,则Candidate自动变成Leader,开始广播数据。

因为已经提交的日志一定被复制到了多数节点上,所以日志长度等于或者长于多数节点的Candidate一定包含了所有已经提交的日志。

 

为什么不是检查Commit Index?

因为Leader故障时,很有可能只有Leader的Commit Index是最大的。

如果图中的Candidate A被选举为Leader,那么日志4就会被丢弃。但是日志4已经在原来的Leader上提交了,因此必须被保留才行。所以只能让日志长度更长的Candidate B选为Leader。这种做法有可能把原来Leader没广播完成的日志(图中的日志5)接着广播完成,这没有什么关系。

 

- Followers日志补齐

当Leader故障时,Followers上的日志状态是不一样的,有长有短。因此新的Leader选出后,首先要将所有Followers的日志补齐才行。因此Leader要询问Followers的日志长度,从最小的日志位置开始补齐。

- Followers未提交日志的更新

新Leader的日志一定包含所有已经提交的日志。但新Leader的日志不一定是最长的,那些新Leader没有的日志,一定是未提交的日志,因此可以被更新,没有关系的。Leader只需要从自己的当前位置开始插入日志并广播出去就可以了。Followers会用新的日志去更新指定位置上的日志。

4 - 新旧Leader的交替
新的Leader选出后,开始广播日志。这时如果旧的Leader故障恢复了(比如网络临时中断),并且还认为自己是Leader,也会广播日志。这不就导致了同时有两个Leader出现吗?是的,Raft也没办法让旧的Leader不发日志,但是Raft有办法让Followers拒绝旧Leader的日志。

- Term
Raft将时间划分为连续的时间段,称为Term。 Term是指从一次Leader选举开始到下一次Leader选举的一段时间。这段时间内只能有一个Leader被选举成功,并负责管理系统或者没有Leader选出。

Raft论文上的Term图片

每个Term都有一个唯一的数字编号。所有Term的数字编号是从小到大连续排列的。

- 作废旧Leader

Term编号在作废旧Leader的过程中至关重要,但却十分简单。过程如下:

  1. 发送日志到所有Followers,Leader的Term编号随日志一起发送

  2. Followers收到日志后,检查Leader的Term编号。如果Leader的Term编号等于或者大于自己的当前Term(Current Term)编号,则存储日志到队列并且应答收到日志。否则发送失败消息给Leader,消息中包含自己的当前Term编号。

  3. 当Leader收到任何Term编号比自己的Term编号大的消息时,则将自己变成Follower。收到的消息包括:Follower给自己的回复消息、新Leader的日志广播消息、Leader的选举消息。

- Raft的实现

论文中作者仅用了两个RPC就实现了Raft的功能,它们分别是:

  • RequestVote() Candidate发起的投票请求

  • AppendEntries() 将日志广播到Followers上

AppendEntries()除了广播日志外,作者还巧妙的用它实现了以下的功能:

    • 发送心跳(heartbeat): 没有客户日志时,通过AppendEntries()广播空日志,当做心跳。

    • 发送Commit Index:当Commit Index更新后,可以随着当前的日志通过AppendEntries()广播到Followers上。如果没有客户端日志,则可以随着心跳广播出去。

分布式系统的Raft算法学习笔记的更多相关文章

  1. C / C++算法学习笔记(8)-SHELL排序

    原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...

  2. Manacher算法学习笔记 | LeetCode#5

    Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...

  3. Johnson算法学习笔记

    \(Johnson\)算法学习笔记. 在最短路的学习中,我们曾学习了三种最短路的算法,\(Bellman-Ford\)算法及其队列优化\(SPFA\)算法,\(Dijkstra\)算法.这些算法可以快 ...

  4. 某科学的PID算法学习笔记

    最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...

  5. Johnson 全源最短路径算法学习笔记

    Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...

  6. 学习Raft算法的笔记

    Raft是一种为了管理日志复制的一致性算法.它提供了和Paxos算法相同的功能和性能,但是它的算法结构和Paxos不同,使得Raft算法更加容易理解并且更容易构建实际的系统.为了提升可理解性,Raft ...

  7. Raft论文学习笔记

    先附上论文链接  https://pdos.csail.mit.edu/6.824/papers/raft-extended.pdf 最近在自学MIT的6.824分布式课程,找到两个比较好的githu ...

  8. 分布式系统的Raft算法

    好东西~~ 英文动画演示Raft 过去, Paxos一直是分布式协议的标准,但是Paxos难于理解,更难以实现,Google的分布式锁系统Chubby作为Paxos实现曾经遭遇到很多坑. 来自Stan ...

  9. 分布式系统的Raft算法——在失联阶段这个老Leader的任何更新都不能算commit,都回滚,接受新的Leader的新的更新 意味着还是可能丢数据!!!

    过去, Paxos一直是分布式协议的标准,但是Paxos难于理解,更难以实现,Google的分布式锁系统Chubby作为Paxos实现曾经遭遇到很多坑. 来自Stanford的新的分布式协议研究称为R ...

随机推荐

  1. Borg Maze(BFS+MST)

    Borg Maze http://poj.org/problem?id=3026 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions ...

  2. Server.Transfer和Response.Redirect的区别

    (1)Server.Transfer方法: Server.Transfer("m2.aspx");//页面转向(服务器上执行). 服务器停止解析本页,保存此页转向前的数据后,再使页 ...

  3. mysql 一次性插入上万条数据测试专用

    无聊期间 记录下 mysql 一次性插入上万条数据 测试的时候可以用 首先 创建一个表 t3 create table t3(id int)ENGINE = MyISAM; \d //    表示吧m ...

  4. Multiply Strings大整数乘法

    [抄题]: 以字符串的形式给定两个非负整数 num1 和 num2,返回 num1 和 num2 的乘积. [暴力解法]: 时间分析: 空间分析: [思维问题]: 还要找到结果中第一位不等于0的数再添 ...

  5. 稀疏矩阵乘法 · Sparse Matrix Multiplication

    [抄题]: 给定两个 稀疏矩阵 A 和 B,返回AB的结果.您可以假设A的列数等于B的行数. [暴力解法]: 时间分析: 空间分析: [思维问题]: [一句话思路]: 如果为零则不相乘,优化常数的复杂 ...

  6. rtx自定义面板不更新

    服务器和客户端自定义面的文件分别在下列xml中. 程序员的基础教程:菜鸟程序员

  7. ubuntu开机执行指令或脚本

    vi /etc/rc.d/rc.localz 将指令添加到exit 0之前,保存.

  8. 数据备份——PHP

    在大多数情况下,开发实在win下进行,因此,然系统每天自动备份数据这也是有必要的饿. Windows平台数据备份 创建批处理文件 在批处理文件中填写如下代码: D:\wamp64\bin\php\ph ...

  9. background image

    http://www.ajaxblender.com/bgstretcher-2-jquery-stretch-background-plugin-updated.html http://blog.d ...

  10. mongo学习-group操作以及java代码

    原数据: /* 1 */ { "_id" : ObjectId("552a330e05c27486b9b9b650"), "_class" ...