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. OAuth2.0学习(1-8) 授权方式五之Access_Token令牌过期更新

    OAuth2.0的Access_Token令牌过期更新 如果用户访问的时候,客户端的"访问令牌"已经过期,则需要使用"更新令牌"申请一个新的访问令牌. 客户端发 ...

  2. Django 使用celery任务队列的配置

    celery 情景:用户发起request,并等待response返回.在本些views中,可能需要执行一段耗时的程序,那么用户就会等待很长时间,造成不好的用户体验,比如发送邮件.手机验证码等. 使用 ...

  3. python当中的 可迭代对象 迭代器

    学习python有一段时间了,在学习过程中遇到很多难理解的东西,做一下总结,希望能对其他朋友有一些帮助. 完全是个人理解,难免有错,欢迎其他大神朋友们批评指正. 1 迭代 什么是迭代呢??我们可以这样 ...

  4. MYSQL之索引原理与慢查询优化

    一.索引 1.介绍 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们遇到最多的也是最容易出现问题的,还是一些复杂的查询操作,因此对查询语句的优化 ...

  5. tensorflow让程序学习到函数y = ax + b中a和b的值

    今天我们通过tensorflow来实现一个简单的小例子: 假如我定义一个一元一次函数y = 0.1x + 0.3,然后我在程序中定义两个变量 Weight 和 biases 怎么让我的这两个变量自己学 ...

  6. Scrollbar

    Scrollbar(滚动条)组件用于滚动一些组件的可见范围,可分为垂直和水平的. 用法: from tkinter import * root =Tk() #滚动条组件 sb = Scrollbar( ...

  7. 1025InnoDB log file 设置多大合适

    转自 http://blog.csdn.net/langkeziju/article/details/51094289 数据库的东西,往往一个参数就牵涉N多知识点.所以简单的说一下.大家都知道inno ...

  8. Python模块 - re

    Python 的 re 模块(Regular Expression 正则表达式)提供各种正则表达式的匹配操作,在文本解析.复杂字符串分析和信息提取时是一个非常有用的工具,下面我主要总结了re的常用方法 ...

  9. 关于Unity中NGUI图片精灵响应鼠标的方法

    我在Unity里做NGUI的时候发现一个问题. 在Unity2D场景当中,一个精灵图片只要加上了Box Collider或者Box Collider2D,就可以相应OnMouseEnter和OnMou ...

  10. 各种电脑进入BIOS快捷键

    组装机主板 品牌笔记本 品牌台式机 主板品牌 启动按键 笔记本品牌 启动按键 台式机品牌 启动按键 华硕主板 F8 联想笔记本 F12 联想台式机 F12 技嘉主板 F12 宏基笔记本 F12 惠普台 ...