介绍

Raft是一种为了管理复制日志的一致性算法。为了提升可理解性,Raft 将一致性算法分解成了几个关键模块,例如领导人选举、日志复制和安全性。同时它通过实施一个更强的一致性来减少需要考虑的状态的数量。同时,raft还提供了集群变更的应对方法。

Raft独有特性:

  1. 强领导者:日志条目只从领导者发送给其他的服务器
  2. 领导选举:Raft 算法使用一个随机计时器来选举领导者
  3. 关系调整:Raft 使用一种共同一致的方法来处理集群成员变换的问题

Raft一致性算法

Raft 基础

一个 Raft 集群包含若干个服务器节点;通常是 5 个,这允许整个系统容忍 2 个节点的失效。

  • 领导者:领导人处理所有的客户端请求(如果一个客户端和跟随者联系,那么跟随者会把请求重定向给领导人)。
  • 跟随者:他们不会发送任何请求,只是简单的响应来自领导者或者候选人的请求。
  • 候选人,选举新领导人时使用

一些相关状态

状态 所有服务器上持久存在的
currentTerm 服务器最后一次知道的任期号(初始化为 0,持续递增)
votedFor 在当前获得选票的候选人的 Id
log[] 日志条目集;每一个条目包含一个用户状态机执行的指令,和收到时的任期号
状态 所有服务器上经常变的
commitIndex 已知的最大的已经被提交的日志条目的索引值
lastApplied 最后被应用到状态机的日志条目索引值(初始化为 0,持续递增)
状态 在领导人里经常改变的 (选举后重新初始化)
nextIndex[] 对于每一个服务器,需要发送给他的下一个日志条目的索引值(初始化为领导人最后索引值加一)
matchIndex[] 对于每一个服务器,已经复制给他的日志的最高索引值

所有服务器需遵守的规则

所有服务器:

if(commitIndex > lastApplied){
那么就 lastApplied 加一,并把log[lastApplied]应用到状态机中;
} if(T > currentTerm){
currentTerm 等于 T,并切换状态为跟随者
}

跟随者

  1. 响应来自候选人和领导者的请求;
  2. 如果在超过选举超时时间的情况之前都没有收到领导人的心跳,或者是候选人请求投票的,就自己变成候选人

候选人

  1. 在转变成候选人后就立即开始选举过程

    1. 自增当前的任期号(currentTerm)
    2. 给自己投票
    3. 重置选举超时计时器
    4. 发送请求投票的 RPC 给其他所有服务器
  2. 如果接收到大多数服务器的选票,那么就变成领导人
  3. 如果接收到来自新的领导人的附加日志 RPC,转变成跟随者
  4. 如果选举过程超时,再次发起一轮选举

领导人

  1. 一旦成为领导人:发送空的附加日志 RPC(心跳)给其他所有的服务器;在一定的空余时间之后不停的重复发送,以阻止跟随者超时
  2. 如果接收到来自客户端的请求:附加条目到本地日志中,在条目被应用到状态机后响应客户端
  3. 如果对于一个跟随者,最后日志条目的索引值大于等于nextIndex,发送从 nextIndex 开始的所有日志条目
    1. 如果成功:更新相应跟随者的 nextIndex 和 matchIndex
    2. 如果因为日志不一致而失败,减少 nextIndex 重试

领导人选举

如果跟随者一段时间没有接受到Leader的任何消息,开始超时选举。竞选者增加当前term号,向其他节点请求选票。他保持当前状态,直到以下三种情况发生。

  1. 赢得本次选举
  2. 其它服务器赢得选举
  3. 选举超时

请求投票 RPC

参数 解释
term 候选人的任期号
candidateId 请求选票的候选人的 Id
lastLogIndex 候选人的最后日志条目的索引值
lastLogTerm 候选人最后日志条目的任期号
返回值 解释
term 当前任期号,以便于候选人去更新自己的任期号
voteGranted 候选人赢得了此张选票时为真

接收者实现:

if(term < currentTerm){
return false;
}
//先来先投票原则,并且只投票给大多数
if(voteFor为空 || 参与者就是接收者){
if(候选人的日志和自己的一样新)
return true;
}

日志复制

日志遵循一下特性:

  1. 如果在不同的日志中的两个条目拥有相同的索引和任期号,那么他们存储了相同的指令
  2. 如果在不同的日志中的两个条目拥有相同的索引和任期号,那么他们之前的所有日志条目也全部相同

第一个特性来自这样的一个事实,领导人最多在一个任期里在指定的一个日志索引位置创建一条日志条目,同时日志条目在日志中的位置也从来不会改变。第二个特性由附加日志 RPC 的一个简单的一致性检查所保证。在发送附加日志 RPC 的时候,领导人会把新的日志条目紧接着之前的条目的索引位置和任期号包含在里面。如果跟随者在它的日志中找不到包含相同索引位置和任期号的条目,那么他就会拒绝接收新的日志条目。

附加日志 RPC

由领导人负责调用来复制日志指令;也会用作heartbeat

参数 解释
term 领导人的任期号
leaderId 领导人的 Id,以便于跟随者重定向请求
prevLogIndex 新的日志条目紧随之前的索引值
prevLogTerm prevLogIndex 条目的任期号
entries[] 准备存储的日志条目(表示心跳时为空;一次性发送多个是为了提高效率)
leaderCommit 领导人已经提交的日志的索引值
返回值 解释
term 当前的任期号,用于领导人去更新自己
success 跟随者包含了匹配上 prevLogIndex 和 prevLogTerm 的日志时为真
//接收者实现:
//Leader肯定有最大的term
if (term < currentTerm)
return false;
if(prevLogIndex位置上的term和prevLogTerm不匹配){
删除这一条之后所有的日志;
return false;
}
附加任何在已有的日志中不存在的条目;
if(leaderCommit > commitIndex){
leaderCommit = min(leaderCommit, 新日志条目索引值);
}
return true;

安全性

选举限制

Raft 使用投票的方式来阻止候选人赢得选举除非这个候选人包含了所有已经提交的日志条目。

  1. 如果两份日志最后的条目的任期号不同,那么任期号大的日志更加新。
  2. 如果两份日志最后的条目任期号相同,那么日志比较长的那个就更加新。

提交之前任期内的日志条目

主要是对commit的定义:只有它自己提交当前term号的操作才能将之前的日志看作是真正的可以提交。

一个领导人不能断定一个之前任期里的日志条目被保存到大多数服务器上的时候就一定已经提交了。

  1. (a) 中,S1 是领导者,部分的复制了索引位置 2 的日志条目。
  2. (b) 中,S1 崩溃了,然后 S5 在任期 3 里通过 S3、S4 和自己的选票赢得选举,然后从客户端接收了一条不一样的日志条目放在了索引 2 处。
  3. (c),S5 又崩溃了;S1 重新启动,选举成功,开始复制日志。在这时,来自任期 2 的那条日志已经被复制到了集群中的大多数机器上,但是还没有被提交。
  4. 如果 S1 在 (d) 中又崩溃了,S5 可以重新被选举成功(通过来自 S2,S3 和 S4 的选票),然后覆盖了他们在索引 2 处的日志。但是,在崩溃之前,如果 S1 在自己的任期里复制了日志条目到大多数机器上
  5. 如 (e) 中,然后这个条目就会被提交(S5 就不可能选举成功)。 在这个时候,之前的所有日志就会被正常提交处理。

图中展示了一种情况,一条已经被存储到大多数节点上的未提交的老日志条目(这不是废话吗?),也依然有可能会被未来的领导人覆盖掉。

只有它自己提交当前term的操作才能看作是真正的提交。(leader只有提交了当前term号的日志后才能将之前的日志应用到状态机)

成员组变更

成员组变更的难点

  1. 成员组正常Paxos日志同步服务不中断
  2. 任何情况下宕机都能够保证存活的多数派成员间能够选举leader
  3. 不会出现1个以上的多数派选出大于1个leader的情况

基本思路

  1. “旧朝代”的多数派成员对“旧朝代结束”这件事达成一致,达成一致后旧成员组不再投票
  2. “新朝代”的多数派成员对“新朝代开启”这件事达成一致,达成一致后新成员组开始投票

上面的思路可以满足难点3,但是不能满足难点1,2。比如Pa执行成功后,在Pb执行成功之前:没有成员组可以投票,服务会中断;如果集群宕机重启,新的成员组的各个成员由于还未对新成员组达成一致,而无法选出leader。

Joint-Consensus

通用成员组变更方法--Joint-Consensus

  • 变更操作
  1. 成员变更操作前,C(old)的多数派中持久化的成员组为[[C(old)]]
  2. 成员变更操作由leader执行,leader收到命令后,将成员组[[C(old),C(new)]]发送给C(old)∪C(new)的所有成员,在此之后新的日志同步需要保证得到C(old)和C(new)两个多数派的确认
  3. leader收到C(old)和C(new)两个多数派确认后,将成员组[[C(new)]]发送给C(new)的所有成员,收到C(new)多数派确认后,表示成员变更成功,后续的日志只要得到C(new)多数派确认即可
  • 投票规则
  1. 持有[[C(old),C(new)]]的候选人要得到C(old)和C(new)两个多数派都确认,才能当选leader
  2. 持有[[C(old)]]的候选人要得到C(old)多数派确认,才能当选leader
  3. 持有[[C(new)]]的候选人要得到C(new)多数派确认,才能当选leader

总结

  1. 领导者选举
  2. 普通附加操作
  3. 安全性和一致性
  4. 平衡旧领导者:出现网络分区,通过Term号使旧领导者变为follower
  5. 客户端交互:只有leader和客户端交互
  6. 更改配置

从raft论文出发的更多相关文章

  1. 【转】分布式一致性算法:Raft 算法(Raft 论文翻译)

    编者按:这篇文章来自简书的一个位博主Jeffbond,读了好几遍,翻译的质量比较高,原文链接:分布式一致性算法:Raft 算法(Raft 论文翻译),版权一切归原译者. 同时,第6部分的集群成员变更读 ...

  2. raft 论文

    raft 论文,摘自  http://www.infoq.com/cn/articles/raft-paper raft动画:https://raft.github.io/ raft说明动画:

  3. Raft论文《 In Search of an Understandable Consensus Algorithm (Extended Version) 》研读

    Raft 论文研读 说明:本文为论文 < In Search of an Understandable Consensus Algorithm (Extended Version) > 的 ...

  4. Raft论文的一些问题

    抛些问题出来,真正解释了这些问题才算理解了论文.:) 1. 什么是复制状态机 2. Raft vs Paxos 3. Raft的设计目标understandability,为达到设计目标在做设计时如何 ...

  5. Raft论文学习笔记

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

  6. Raft论文概述

    介绍 Raft是一种为了管理复制日志的一致性算法.为了提升可理解性,Raft 将一致性算法分解成了几个关键模块,例如领导人选举.日志复制和安全性.同时它通过实施一个更强的一致性来减少需要考虑的状态的数 ...

  7. Raft与MongoDB复制集协议比较

    在一文搞懂raft算法一文中,从raft论文出发,详细介绍了raft的工作流程以及对特殊情况的处理.但算法.协议这种偏抽象的东西,仅仅看论文还是比较难以掌握的,需要看看在工业界的具体实现.本文关注Mo ...

  8. 分布式一致性算法:Raft 算法(论文翻译)

    Raft 算法是可以用来替代 Paxos 算法的分布式一致性算法,而且 raft 算法比 Paxos 算法更易懂且更容易实现.本文对 raft 论文进行翻译,希望能有助于读者更方便地理解 raft 的 ...

  9. 解读Raft(二 选举和日志复制)

    Leader election Raft采用心跳机制来触发Leader选举.Leader周期性的发送心跳(如果有正常的RPC的请求情况下可以不发心跳)包保持自己Leader的角色(避免集群中其他节点认 ...

随机推荐

  1. hdu 4998 矩阵表示旋转

    http://acm.hdu.edu.cn/showproblem.php?pid=4998 http://blog.csdn.net/wcyoot/article/details/33310329 ...

  2. 【转】如何使用BehaviorSDK

    原文地址:http://blogs.msdn.com/b/windows8devsupport/archive/2014/10/24/behaviorsdk.aspx 前言 在开发过程中,程序员一般通 ...

  3. SQL Server 统计信息(Statistics)-概念,原理,应用,维护

    前言:统计信息作为sql server优化器生成执行计划的重要参考,需要数据库开发人员,数据库管理员对其有一定的理解,从而合理高效的应用,管理. 第一部分 概念 统计信息(statistics):描述 ...

  4. JWT+Log4net配置与使用

    Log4net的优点        log4net是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介.程序运行过 ...

  5. 在Windows安装Reids 详解

    今天安装了redis,记录点经验 因为Redis项目没有正式支持Windows. 但Microsoft开发和维护一个针对Windows 64版的redis. 下载地址在微软的GitHub上,地址:ht ...

  6. ProtoBuf序列化和反序列化方法

    最近公司需要将以前的协议全都改成ProtoBuf生成的协议,再将结构体打包和解包过程终于到一些问题 ,无法使用Marshal.SizeOf计算结构体大小,最后找了一下ProtoBuf的文档,可以用它自 ...

  7. 在微信开发中如果WeixinJSBridge.call('closeWindow');关闭窗口无效!

    原因是,成功后页面跳转到普通页面.必须在前面加上 parent.WeixinJSBridge.call('closeWindow'); 这样才行.如果是使用了iframe页面,这样也可以关闭网页,回到 ...

  8. 使用chosen插件实现多级联动和置位

    使用chosen插件实现多级联动和置位 首先写好第一个select,加上onchage属性之后,写onchange方法. <select data-placeholder="选择省份. ...

  9. 网易云社区有奖问答活动第二期——技术领导力、深入分布式、PHP圣经、Linux运维、Unity……三月热点图书等你拿!

    网易云社区第二期有奖问答活动开始了!(第一期活动已结束:人工智能图书大抽奖!) 欢迎积极参与网易云社区,讨论问题,交流心得.我们本期准备了一批技术领域热点图书,送给参与社区的朋友们,将以抽奖的形式送出 ...

  10. FFmpeg编写的代码

    //初始化解封装    av_register_all();    avformat_network_init();    avcodec_register_all();    //封装文件的上下文  ...