2019独角兽企业重金招聘Python工程师标准>>>

一、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协议如下图所示:

二、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同时存在。相反,数据广播的过程则变的简单易于理解了。

三、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的日志队列和《》中的“预存储队列+存储队列”功能是一样的,但是巧妙的合并到了一起。这样做解决的问题和中“预存储队列+存储队列”解决的问题也是一样的,这里就不再叙述。

四、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会用新的日志去更新指定位置上的日志。

五、新旧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上。如果没有客户端日志,则可以随着心跳广播出去。

转载于:https://my.oschina.net/u/1174461/blog/1864000

深入浅出分布式系统Raft协议相关推荐

  1. 理解分布式一致性:Raft协议

    理解分布式一致性:Raft协议 什么是分布式一致性 Leader选举 日志复制流程 term选举周期 timeout 选举和选举timeout 选举分裂 日志复制和心跳timeout 在分布式系统中, ...

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

    前言 在分布式系统中,为了保证容错性,一般会维护多个副本集群,提高系统的高可用,但与之带来的问题就是多个副本的一致性(consensus)问题. 我们认为,对于一个具有一致性的的集群中,同一时刻所有节 ...

  3. DLedger —基于 raft 协议的 commitlog 存储库

    尊敬的阿里云用户: 您好!为方便您试用开源 RocketMQ 客户端访问阿里云MQ,我们申请了专门的优惠券,优惠券可以直接抵扣金额.请填写下您公司账号信息,点击上图,了解更多哦. 一.DLedger引 ...

  4. 讨论帖:如果只有两个数据中心,使用 Raft 协议还有意义吗?

    作者:disksing 对 Raft 有所了解的同学都知道,Raft 一般会使用奇数个节点,比如 3.5.7 等等.这是因为 Raft 是 一种基于多节点投票选举机制的共识算法,通俗地说,只有超过半数 ...

  5. Raft协议中文翻译(1)

    #写在前面 一直以来, 对Raft协议的理解感觉都没有非常到位, 本着眼过千遍, 不如手过一遍的原则, 利用空闲时间, 就自己把Raft翻译一遍, 加深自己的理解, 也方便其他同学参考. Raft协议 ...

  6. ZAB、Raft协议简述

    CAP原则 1.一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值,即写操作之后的读操作,必须返回该值.(分为弱一致性.强一致性和最终一致性) 2.可用性(A):在集群中一部分节点故障 ...

  7. Nacos如何实现Raft算法与Raft协议原理详解

    前言 大名鼎鼎的Paxos算法可能不少人都听说过,几乎垄断了一致性算法领域,在Raft协议诞生之前,Paxos几乎成了一致性协议的代名词.但是对于大多数人来说,Paxos算法太难以理解了,而且难以实现 ...

  8. Raft协议学习笔记

    目录 目录 1 1. 前言 1 2. 名词 1 3. 什么是分布式一致性? 3 4. Raft选举 3 4.1. 什么是Leader选举? 3 4.2. 选举的实现 4 4.3. Term和Lease ...

  9. SpringCloud Alibaba(五)Nacos raft协议介绍

    前一章,我们了解了当Nacos客户端注册的节点为临时节点时,服务端的一致性协议使用的Distro协议,那么当我们的客户端注册节点为非临时节点的时候,他用的一致性协议是raft协议,下面,我们就来介绍一 ...

  10. Raft协议详解(一)前言:子问题分解

    分布式一致性,一直是分布式系统中非常重要的部分.在多机集群中,如何保证不同服务器上同一副本的数据是一致正确的,如何保证在故障频发的集群中数据能够安全保存等问题,都需要靠分布式一致性来解决.在对分布式一 ...

最新文章

  1. python subprocess库 终端命令行命令
  2. 使用ListView应该注意的地方 很全
  3. k8s系列---部署集群
  4. 信息系统项目管理师-信息系统范围管理核心知识点思维脑图
  5. The method setClass(Context, Class?) in the type Intent is not applicable for the arguments (GameV
  6. SAP Hybris的Convertor, Populator, Facade和DTO这几个概念是如何协同工作的
  7. Linux命令 — 设置或查看网络配置命令ifconfig
  8. c# 中wpfexcel_VS2017下编写C#程序读写Excel文件
  9. 【LeetCode】剑指 Offer 31. 栈的压入、弹出序列
  10. c语言中数组的变量j是什么,c语言中数组,一般数组
  11. IE8不能上传、插入图片的解决办法!
  12. RabbitMQ 中的 7 种队列模式,写得太好了!
  13. MySQL 优化1
  14. 基于Web的在线教师备课系统
  15. 四十四 老李来了 我在软件园的那些日子里
  16. 特种浓缩分离:无机陶瓷膜元件及设备
  17. 塑胶模具设计中的几个小问题,学会不吃亏
  18. Winyao 8125-M2-C NGFF KEY A+E RTL8125B 工业2.5G千兆网卡
  19. 二层与三层交换机之间有什么区别?
  20. Google安全浏览算法更新:屡教不改的站点将被屏蔽30天

热门文章

  1. cookie和session基础以及在Django中应用
  2. MySql学习笔记【二、库相关操作】
  3. spark streaming之 windowDuration、slideDuration、batchDuration​
  4. mysql 分组之后统计记录条数
  5. HTML5的绘画支持(五)
  6. IPhone开发从零开始之1-构思你的产品
  7. CString.Format详解【摘录】
  8. 阿里云负载均衡SSL证书配置(更新)
  9. 第八节,改善深层神经网络:超参数调试、正则化及梯度下降算法(中)
  10. 不常用的SQL语句记录