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算法的Leader选举和日志复制过程

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

  2. Go实现Raft第三篇:命令和日志复制

    女主宣言 今天小编为大家分享一篇关于Golang实现Raft的文章,本篇文章为系列中的第三篇,对Raft中的命令和日志复制进行介绍并使用go进行实现.希望能对大家有所帮助. PS:丰富的一线技术.多元 ...

  3. 快速理解Raft之日志复制(肝了两千五百字)

    一.日志复制背景 当raft集群选出领导者的时候,集群就开始提供服务了.这个时候,会有客户端向raft集群发出请求.请求里面会包含一个可以被raft状态机执行的命令.leader会把这个命令作为一个e ...

  4. Raft 实现日志复制同步

    本篇文章以 John Ousterhout(斯坦福大学教授) 和 Diego Ongaro(斯坦福大学获得博士学位,Raft算法发明人) 在 Youtube 上的讲解视频及 PPT 为蓝本,深入分析 ...

  5. Raft算法实现 - Sofa-JRaft,选主,数据写入,日志复制

    关于raft算法相关细节,可以全看之前的文章 分布式一致性算法,两阶段提交,三阶段提交,Paxos,Raft,zookeeper的选主过程,zab协议,顺序一致性,数据写入流程,节点状态,节点的角色 ...

  6. Paxos 实现日志复制同步(Multi-Paxos)

    Paxos 实现日志复制同步 这篇文章以一种易于理解的方式来解释 Multi-Paxos 的机制. Multi-Paxos 的是为了创建日志复制 一种实现方式是用一组基础 Paxos 实例,每条记录都 ...

  7. 企业级高性能MYSQL的用法---------(二)----------半同步复制 和 全同步复制(组复制)

    企业级高性能MYSQL的用法---------(二)----------半同步复制 和 全同步复制(组复制) 1.基于GDIT的半同步复制 为什么要实现mysqI的复制 1.实现服务器负载均衡 2.通 ...

  8. Zookeeper源码分析(二) ----- zookeeper日志

    zookeeper源码分析系列文章: Zookeeper源码分析(一) ----- 源码运行环境搭建 原创博客,纯手敲,转载请注明出处,谢谢! 既然我们是要学习源码,那么如何高效地学习源代码呢?答案就 ...

  9. Raft 共识算法3-日志复制

    Raft 共识算法3-日志复制 Raft算法中译版地址:https://object.redisant.com/doc/raft%E4%B8%AD%E8%AF%91%E7%89%88-2023%E5% ...

最新文章

  1. 数据统计之日活跃用户统计
  2. 干货丨机器学习知识点(人工智能篇)
  3. python单目运算_Python -- 数字
  4. web.xml中load-on-startup的作用
  5. 一次对路边饮用水RFID供应机的跑路玩法
  6. python计算面积折线图_Python交互图表可视化Bokeh:4. 折线图| 面积图
  7. RuntimeError: freeze_support()
  8. RedHat Linux 启动FTP
  9. linux awk菜鸟教程,Linux awk 命令
  10. 【Java】冒泡排序
  11. Java之intern方法
  12. 那个男人 ,他带着Vue3来了~
  13. 网络爬虫之Xpath用法汇总
  14. UCLA教授朱松纯:走向通用人工智能,从大数据到大任务
  15. mysql性能监控 调优_MySQL管理之道:性能调优、高可用与监控(第2版)
  16. 随机函数c语言对打,20165323 学习基础和C语言基础调查
  17. 大数据是让人幸福的科学
  18. LM2596 负载增大,电压降低的问题
  19. cat /etc/sysconfig/network-scripts/ifcfg-ens33
  20. 《被讨厌的勇气》读后感

热门文章

  1. 从Netty到EPollSelectorImpl学习Java NIO
  2. 说说JSON和JSONP,也许你会豁然开朗
  3. Java集合框架中Map接口的使用
  4. MLS 移动最小二乘
  5. System.getProperty()参数大全
  6. 大数据分析常用去重算法分析『HyperLogLog 篇』
  7. 从头开始学py,列表,字符串
  8. 获取jar中的资源文件途径
  9. 第5章:可复用性的软件构建方法 5.2面向复用的构造
  10. 怎样初始化一个指针数组