注:本文原创,转载请标明出处。

欢迎转发、关注微信公众号:Q的博客。 不定期发送干货,实践经验、系统总结、源码解读、技术原理。

本文目的

笔者期望通过系列文章帮助读者深入理解Raft协议并能付诸于工程实践中,同时解读不易理解或容易误解的关键点。

该系列会从原理、源码、实践三个部分为大家讲解Raft算法,本文为《Raft实战》系列第二篇:

原理部分我们会结合 Raft 论文讲解 Raft 算法思路,整体分篇会遵循 Raft 的模块化思想,分别讲解 Leader election、Log replication、Safety、Cluster membership change、Log compaction 等。

源码部分我们会通过分析 hashicorp/raft 来学习一个工业界的 Raft 实现,hashicorp/raft 是 Consul 的底层依赖。

实践部分我们会基于 hashicorp/raft 来实现一个简单的分布式 kv 存储,以此作为系列的收尾。

什么是选主

选主(Leader election)就是在分布式系统内抉择出一个主节点来负责一些特定的工作。在执行了选主过程后,集群中每个节点都会识别出一个特定的、唯一的节点作为leader。

我们开发的系统如果遇到选主的需求,通常会直接基于 zookeeper 或 etcd 来做,把这部分的复杂性收敛到第三方系统。然而作为 etcd 基础的 raft 自身也存在“选主”的概念,这是两个层面的事情:基于 etcd 的选主指的是利用第三方 etcd 让集群对谁做主节点的决策达成一致,技术上来说利用的是 etcd 的一致性状态机、lease 以及 watch 机制,这个事情也可以改用单节点的 MySQL/Redis 来做,只是无法获得高可用性;而 raft 本身的选主则指的是在 raft 集群自身内部通过票选、心跳等机制来协调出一个大多数节点认可的主节点作为集群的 leader 去协调所有决策。

当你的系统利用 etcd 来写入谁是主节点的时候,这个决策也在 etcd 内部被它自己集群选出的主节点处理并同步给其它节点。

Raft 为什么要进行选主?

按照论文所述,原生的 Paxos 算法使用了一种点对点(peer-to-peer)的方式,所有节点地位是平等的。在理想情况下,算法的目的是制定一个决策,这对于简化的模型比较有意义。但在工业界很少会有系统会使用这种方式,当有一系列的决策需要被制定的时候,先选出一个 leader 节点然后让它去协调所有的决策,这样算法会更加简单快速。

此外,和其它一致性算法相比,raft 赋予了 leader 节点更强的领导力,称之为 Strong Leader。比如说日志条目只能从 leader 节点发送给其它节点而不能反着来,这种方式简化了日志复制的逻辑,使 raft 变得更加简单易懂。

Raft选主过程

下图的节点状态转移图,我们在前一篇文章已经看到了,但只是做了简单的描述,接下来我们会结合具体的Leader election细节来深刻理解节点的状态转换。

*图名:节点状态图

Follower状态转移过程

Raft 的选主基于一种心跳机制,集群中每个节点刚启动时都是 follower 身份(Step: starts up),leader 会周期性的向所有节点发送心跳包来维持自己的权威,那么首个 leader 是如何被选举出来的呢?方法是如果一个 follower 在一段时间内没有收到任何心跳,也就是选举超时,那么它就会主观认为系统中没有可用的 leader,并发起新的选举(Step: times out, starts election)。

这里有一个问题,即这个“选举超时时间”该如何制定?如果所有节点在同一时刻启动,经过同样的超时时间后同时发起选举,整个集群会变得低效不堪,极端情况下甚至会一直选不出一个主节点。Raft 巧妙的使用了一个随机化的定时器,让每个节点的“超时时间”在一定范围内随机生成,这样就大大的降低了多个节点同时发起选举的可能性。

*图解:一个五节点Raft集群的初始状态,所有节点都是follower身份,term为1,且每个节点的选举超时定时器不同

若 follower 想发起一次选举,follower 需要先增加自己的当前 term,并将身份切换为 candidate。然后它会向集群其它节点发送“请给自己投票”的消息(RequestVote RPC)。

*图解:S1 率先超时,变为 candidate,term + 1,并向其它节点发出拉票请求

Candicate状态转移过程

Follower 切换为 candidate 并向集群其他节点发送“请给自己投票”的消息后,接下来会有三种可能的结果,也即上面节点状态图中 candidate 状态向外伸出的三条线。

1. 选举成功(Step: receives votes from majority of servers)

当candicate从整个集群的大多数(N/2+1)节点获得了针对同一 term 的选票时,它就赢得了这次选举,立刻将自己的身份转变为 leader 并开始向其它节点发送心跳来维持自己的权威。

*图解:“大部分”节点都给了S1选票

*图解:S1变为leader,开始发送心跳维持权威

每个节点针对每个 term 只能投出一张票,并且按照先到先得的原则。这个规则确保只有一个 candidate 会成为 leader。

2. 选举失败(Step: discovers current leader or new term)

Candidate 在等待投票回复的时候,可能会突然收到其它自称是 leader 的节点发送的心跳包,如果这个心跳包里携带的 term 不小于 candidate 当前的 term,那么 candidate 会承认这个 leader,并将身份切回 follower。这说明其它节点已经成功赢得了选举,我们只需立刻跟随即可。但如果心跳包中的 term 比自己小,candidate 会拒绝这次请求并保持选举状态。

*图解:S4、S2 依次开始选举

*图解:S4 成为 leader,S2 在收到 S4 的心跳包后,由于 term 不小于自己当前的 term,因此会立刻切为 follower 跟随S4

3. 选举超时(Step: times out, new election)

第三种可能的结果是 candidate 既没有赢也没有输。如果有多个 follower 同时成为 candidate,选票是可能被瓜分的,如果没有任何一个 candidate 能得到大多数节点的支持,那么每一个 candidate 都会超时。此时 candidate 需要增加自己的 term,然后发起新一轮选举。如果这里不做一些特殊处理,选票可能会一直被瓜分,导致选不出 leader 来。这里的“特殊处理”指的就是前文所述的随机化选举超时时间。

*图解:S1~S5都在参与选举

*图解:没有任何节点愿意给他人投票

*图解:如果没有随机化超时时间,所有节点将会继续同时发起选举……

以上便是 candidate 三种可能的选举结果。

Leader 切换状态转移过程

节点状态图中的最后一条线是:discovers server with higher term。想象一个场景:当 leader 节点发生了宕机或网络断连,此时其它 follower 会收不到 leader 心跳,首个触发超时的节点会变为 candidate 并开始拉票(由于随机化各个 follower 超时时间不同),由于该 candidate 的 term 大于原 leader 的 term,因此所有 follower 都会投票给它,这名 candidate 会变为新的 leader。一段时间后原 leader 恢复了,收到了来自新leader 的心跳包,发现心跳中的 term 大于自己的 term,此时该节点会立刻切换为 follower 并跟随的新 leader。

上述流程的动画模拟如下:

*图解:S4 作为 term2 的 leader

*图解:S4 宕机,S5 即将率先超时

*图解:S5 当选 term3 的 leader

*图解:S4 宕机恢复后收到了来自 S5 的 term3 心跳

*图解:S4 立刻变为 S5 的 follower

以上就是 raft 的选主逻辑,但还有一些细节(譬如是否给该 candidate 投票还有一些其它条件)依赖算法的其它部分基础,我们会在后续“安全性”一篇描述。

当票选出 leader 后,leader 也该承担起相应的责任了,这个责任是什么?就是下一篇将介绍的“日志复制”~

欢迎转发、关注微信公众号:Q的博客,不定期发送干货,实践经验、系统总结、源码解读、技术原理。

raft协议 MySQL 切换_Raft 协议实战系列(二)—— 选主相关推荐

  1. 活动目录实战系列二(主域控无法正常启动)

    今天一大早过来,发现WIN98客户端无法登陆,一检查主域控DOWN机了,没法启动.幸好做了额外DC,通过抢占PDC角色,提升额外DC为主DC,先使客户机正常登录域环境,这样我们为修复主域控争取时间.环 ...

  2. 【Youtobe trydjango】Django2.2教程和React实战系列二【settings配置文件】

    [Youtobe trydjango]Django2.2教程和React实战系列二[settings配置文件] 1. Django项目初始化过程 2. 全貌 3. 详细解释 4. 增加其他配置 1. ...

  3. xen虚拟化实战系列(二)之xen虚拟机安装

    xen虚拟化实战系列文章列表 xen虚拟化实战系列(一)之xen虚拟化环境安装 xen虚拟化实战系列(二)之xen虚拟机安装 xen虚拟化实战系列(三)之xen虚拟机复制 xen虚拟化实战系列(四)之 ...

  4. MP实战系列(二)之集成swagger

    其实与spring+springmvc+mybatis集成swagger没什么区别,只是之前写的太不好了,所以这次决定详细写. 提到swagger不得不提rest,rest是一种架构风格,里面有对不同 ...

  5. raft算法mysql主从复制_Raft算法赏析

    前言 最近抽空看了大名鼎鼎的Raft算法论文,看完后就一个感觉:如此复杂的算法居然可以设计得如此简洁.巧妙. 反复看了几遍,非常过瘾,原文不仅通俗易懂,而且非常严谨,所有异常情况都做了充分的考虑以及给 ...

  6. delphi 登录界面 主窗体 切换_Python GUI项目实战(二)主窗体的界面设计与实现

    前言 上一节我们介绍了Python GUI项目实战(一)登录窗体的设计与实现,实现了该项目登录窗体的GUI的搭建,用户的账号和密码校验完成后应当跳转到主窗体界面,这一节我们将具体介绍主窗体界面的设计与 ...

  7. 【CA-TA实战系列二】如何创建一个TA

    前言 年末假期的最后一天信誓旦旦的说,希望年前把这个系列做完,最后还是只做了第一篇,因为最近告诉自己不能熬夜了.一晃就是年后的假期倒数第二天了.时间真的好快. 今天就到了学校,老实讲虽然家里也吵吵闹闹 ...

  8. ATTCK实战系列(二)

    vlunstack是红日安全团队出品的一个实战环境,具体介绍请访问:漏洞详情 拓扑结构大体如下: 环境搭建 Kali ip:192.168.111.135 Web Ip1:192.168.111.80 ...

  9. 云计算实战系列二(Linux-用户管理)

    Linux用户管理 1 用户概览 1.1. 用户/组基本概念! ==================================================== Users and group ...

最新文章

  1. cocos2d-x 音效中断问题
  2. 什么是python-三分钟了解什么是Python?python环境搭建
  3. 文巾解题 面试题 01.02. 判定是否互为字符重排
  4. 答与微博前端教主在吃饭时讨论到的一道微软面试题
  5. python从入门到实践15章的几个自己的小程序
  6. Kubernetes使用Jenkins服务器存储所有的kube.config文件
  7. JS OOP -01 面向对象的基础
  8. call stack and stack buffer overflow
  9. 针对视觉位姿估计特征点优化问题的详细研究
  10. 把房子交给“我爱我家”后,我都不敢再进去了
  11. 目标赋予生命的意义和目的
  12. mysql 条件触发器_具有条件的MySQL更新触发器(MySQL Update Trigger with Conditions)
  13. 图解 CSS (2): border - 边框
  14. 2021-08-08索引在小数据量的时候用处不大,但在大数据的时候十分明显
  15. java中常用的缓存流程、缓存分类、缓存问题
  16. 解决:启动word等office相关软件时,比较慢,会卡在一步Foxit PDF Creator COM Add-in很久
  17. 什么是外包公司?要不要去外包公司?
  18. 驱动miniPCIE网络模块EC20硬件电路详解
  19. U盘格式化后空间变小解决方案(常用于做过系统盘的U盘)
  20. 【亲测 | 007】易搜资料 V2.4.3版本 非独立版 亲测无错 | 极致技术工厂

热门文章

  1. vscode中 解决格式化后将单引号变双引号
  2. Docker JFrog Artifactory 7.27.10 maven私服(IDEA 实战篇01) linux
  3. 启动vue项目失败,报错Failed at the node-sass@4.14.1 postinstall script.
  4. IDEA Cannot access alimaven (http://maven.aliyun.com/nexus/content/groups/public/)
  5. JavaScript高级语法打包 - babel插件安装配置报错!Error: Cannot find module ‘@babel/preset-preset.env‘
  6. 配置无密码登录linux,linux ssh无密码登录配置
  7. php dom 换行,PHP DOM XML不会在标记之后打印掉换行符
  8. linux中ssh启动报错,Linux(Ubuntu18)中启动ssh时的报错
  9. C++中关于隐藏的理解
  10. IOS – OpenGL ES 调节图像反色 GPUImageColorInvertFilter