Leader election

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

Follower在收到Leader或者Candidate的RPC请求的情况下一直保持Follower状态。而当一段时间内(election timeout)没有收到请求则认为没有Leader节点而出发选举流程。

选举流程如下:

  1. Follower递增自己的任期并设置为Candidate角色
  2. 投票给自己并且并发的给所有节点发送投票请求
  3. 保持Candidate状态直到:
    • 同一个任期内获得大多数选票,成为Leader(一个节点在一个任期内只能给一个Candidate投票,任期相同则选票先到先得)并给其他节点发送心跳来保持自己的角色
    • 收到其他节点的RPC请求,如果请求中的任期大于等于Candidate当前的任期,认为其他节点成为了Leader,自身转换为Follower;如果其他节点的任期小于自身的任期,拒绝RPC请求并保持Candidate角色
    • 一段时间后仍旧没有Leader(可能是出现了平票的情况),则在选举超时后重新发起一轮选举(递增任期、发送投票请求)

为了避免平票的问题,同时在出现平票的情况后能快速解决,Raft的选举超时时间是在一个区间内随机选择的(150~300ms)。这样尽量把服务器选举时间分散到不同的时间,保证大多数情况下只有一个节点会发起选举。在平票的情况下,每个节点也会在一个随机时间后开始新一轮选举,避免可能出现的一直处于平票的情况。

Log replication

一旦Leader被选举出来后,Leader就开始为集群服务:处理所有的客户端请求并将数据复制到所有节点。

一旦日志被“安全”的复制,那么Leader将这个日志应用到自己的状态机并响应客户端。

如果有节点异常或网络异常,Leader会一直重试直到所有日志都会正确复制到所有节点(日志不允许有空洞,所以每个节点上的日志都是连续的,不能有因为失败引起的空洞)。

日志组织形式如上图,每个日志条目中包含可执行的指令、和日志被创建时的任期号,日志条目也包含了自己在日志中的位置,即index。一旦一个日志条目存在于大多数节点,那么该日志条目是committed的。

Raft算法保证所有committed的日志都是持久化的(日志需要在大多数节点上持久化之后再响应给客户端,这意味着每个Follower节点收到AppendEntry请求后需要持久化到日志之后再响应给Leader),且最终会被所有的状态机执行。

Raft算法保证了以下特性:

  • 如果两个日志条目有相同的index和term,那么他们存储了相同的指令(即index和term相同,那么可定是同一条指令,就是同一个日志条目)
  • 如果不同的日志中有两个日志条目,他们的index和term相同,那么这个条目之前的所有日志都相同

两条规则合并起来的含义:两个日志LogA、LogB,如果LogA[i].index=Log[i]B.index且LogA[i].term=Log[i].term,那么LogA[i]=Log[i]B,且对于任何n < i的日志条目,LogA[n]=LogB[n]都成立。(这个结论显而易见的可以从日志复制规则中推导出来)

一个新Leader被选举出来时,Follower可能是上图中的任何一种情况。

  • (a)(b)可能还没复制到日志
  • (c)(d)可能曾经是Leader,所有包含了多余的日志(这些日志可能被提交了,也可能没提交)
  • (e)可能是成为Leader之后增加了一些日志,但是在Commit之前又编程了Follower角色,且还没有更新日志条目
  • (f)可能是在任期2称为了Leader并追加了日志但是还没提交就Crash了,恢复之后在任期3又成了Leader并且又追加了日志

在Raft中,通过使用Leader的日志覆盖Follower的日志的方式来解决出现像上图的情况(强Leader)。Leader会找到Follower和自己想通的最后一个日志条目,将该条目之后的日志全部删除并复制Leader上的日志。详细过程如下:

  • Leader维护了每个Follower节点下一次要接收的日志的索引,即nextIndex
  • Leader选举成功后将所有Follower的nextIndex设置为自己的最后一个日志条目+1
  • Leader将数据推送给Follower,如果Follower验证失败(nextIndex不匹配),则在下一次推送日志时缩小nextIndex,直到nextIndex验证通过

上面的方式显然可以通过一些方法进行优化来减少重试的次数,但是在Raft论文中对是否有必要进行优化提出了质疑,因为这种异常的情况很少出现。

解读Raft(二 选举和日志复制)的更多相关文章

  1. 图解Raft之日志复制

    日志复制可以说是Raft集群的核心之一,保证了Raft数据的一致性,下面通过几张图片介绍Raft集群中日志复制的逻辑与流程: 在一个Raft集群中只有Leader节点能够接受客户端的请求,由Leade ...

  2. 解读Raft(一 算法基础)

    最近工作中讨论到了Raft协议相关的一些问题,正好之前读过多次Raft协议的那paper,所以趁着讨论做一次总结整理. 我会将Raft协议拆成四个部分去总结: 算法基础 选举和日志复制 安全性 节点变 ...

  3. Raft 实现日志复制同步

    Raft 实现日志复制同步 本篇文章以 John Ousterhout(斯坦福大学教授) 和 Diego Ongaro(斯坦福大学获得博士学位,Raft算法发明人) 在 Youtube 上的讲解视频及 ...

  4. 基于 raft 协议的 RocketMQ DLedger 多副本日志复制设计原理

    目录 1.RocketMQ DLedger 多副本日志复制流程图 1.1 RocketMQ DLedger 日志转发(append) 请求流程图 1.2 RocketMQ DLedger 日志仲裁流程 ...

  5. MySQL复制(二)--基于二进制日志文件(binlog)配置复制

    基础环境:   主库 从库 服务器IP地址 192.168.10.11 192.168.10.12 版本 5.7.24 5.7.24 已存在的数据库 mysql> show databases; ...

  6. Etcd中Raft日志复制的实现

    Raft state of log commitIndex : A log entry is committed once the leader that created the entry has ...

  7. Raft算法系列教程3:日志复制

    1.日志复制的过程 Leader选出后,就开始接收客户端的请求.Leader把请求作为日志条目(Log entries)加入到它的日志中,然后并行的向其他服务器发起 AppendEntries RPC ...

  8. Paxos 实现日志复制同步

    Paxos 实现日志复制同步 本篇文章以 John Ousterhout(斯坦福大学教授) 和 Diego Ongaro(斯坦福大学获得博士学位,Raft算法发明人) 在 Youtube 上的讲解视频 ...

  9. Paxos 实现日志复制同步(Basic Paxos)

    Paxos 实现日志复制同步 本篇文章以 John Ousterhout(斯坦福大学教授) 和 Diego Ongaro(斯坦福大学获得博士学位,Raft算法发明人) 在 Youtube 上的讲解视频 ...

随机推荐

  1. 前端之HTML内容

    一.HTML介绍 1.Web服务本质 当我们在浏览器中输入一个url后打开一个页面这个过程实质是一个网络编程中的sockt服务端接受指令并发送指令的一个过程.本质顺序是: 浏览器发请求——>HT ...

  2. uvalive 5834 Genghis Khan The Conqueror

    题意: 给出一个图,边是有向的,现在给出一些边的变化的信息(权值大于原本的),问经过这些变换后,MST总权值的期望,假设每次变换的概率是相等的. 思路: 每次变换的概率相等,那么就是求算术平均. 首先 ...

  3. 深度学习中Xavier初始化

    "Xavier"初始化方法是一种很有效的神经网络初始化方法,方法来源于2010年的一篇论文<Understanding the difficulty of training ...

  4. 字典的update方法

    >>> dict = {"name":"zara", "age": 7} >>> dict2 = {&q ...

  5. background属性的学习整理转述

    前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! background我们一般用到的的属性有: background-attachment:背景(图片)是否 ...

  6. JProfiler简明使用教程

    JProfile是一款性能瓶颈分析工具,监控粒度可以细化到某一个类包,堪称神器!我安装了一下9.11的版本,并简单说说使用方法. 1:创建一个监控任务 2:选择tomcat版本 3:监控远程服务器 4 ...

  7. Centos下安装 .net Core运行程序

    首先要进行更新下镜像文件 sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc sudo sh -c 'echo -e ...

  8. Spring(5)——Spring 和数据库编程

    传统 JDBC 回顾 JDBC 我们一定不陌生,刚开始学习的时候,我们写过很多很多重复的模板代码: public Student getOne(int id) { String sql = " ...

  9. ACE入门——ACE构建

    ACE(ADAPTIVE Communication Environment),ACE入门的第一课就是要学习怎么在自己的系统上构建ACE. ACE是跨平台的,这是它的一个很重要的特性,ACE支持很多的 ...

  10. Android基础字符串String.md

    问题抛出 String这个常量在我们代码中会经常被用到,那么我们了解 String stringbuffer StringBudilder三者之间的区别吗 问题解答 String 字符串常量,位于常量 ...