手绘raft算法

互联网技术窝 2019-04-07 12:06:05

在现实的分布式系统中,不能可能保证集群中的每一台机器都是100%可用可靠的,集群中的任何机器都可能发生宕机、网络连接等问题导致集群中的某个节点不可用,这样,那个节点的数据就有可能和集群不一致,所以需要有一种机制,来保证在大多数机器都存在的情况下向外提供可靠的数据服务。这里的大多数节点指的是集群半数以上的节点。

raft算法就是一种在分布式系统中解决集群中多节点之间数据一致性的算法。Golang生态圈中大名鼎鼎的etcd就是使用的raft算法来保持数据一致性的,与raft类似的一致性算法还有Paxos算法、Zab协议等。

其实,raft算法维持数据一致性的核心思想很简单,就是:“少数服从多数”。

leader选举

保证数据一致性,最好的方式就是只有唯一的一个节点,唯一的这个节点读,唯一的这个节点写,这样数据肯定是一致的;但是分布式架构显然不可以一个节点,于是,raft算法提出,在集群的所有节点中,需要有一个节点来充当这一个唯一的节点,在一段时间内,只有这一个节点负责读写数据,然后其他节点同步数据。这个唯一的节点叫leader节点,其他负责同步数据的节点叫做follower节点。在集群中,还会有其他状态的节点,例如candidate节点,这种节点只有在选举leader的时候才会有。

节点的leader选举和现实生活中的选举十分类似,就是投票,集群中获票数最多的那个,就是leader节点,所以为防止出现平局的情况(平局的情况也有解决方案,下文会说),一般在部署节点的时候,会将节点数设置为奇数(2n + 1)。

这些节点是如何选举的呢?我们先从follower、leader、candidate这三种状态说起。

在集群中,有三个节点 A 、B、C。

在集群刚刚开始的时候,他们仨都是follower。

过一段时间后,A变成了Candidate,这是要选举了!

为啥A能变成Candidate?凭啥?因为A的election timeout到期了,election timeout是选举超时时间,集群中的每个节点都有一个election timeout,每个节点的election timeout都是150ms ~ 300ms之间的一个随机数。每当节点的election timeout时间到了,就会触发节点变为candidate状态。A的选举超时时间到了,所以A理所当然变为了Candidate。

所以,我们知道,其实A、B、C三个节点除了有状态,还有个选举超时时间election timeout

此时,candidate节点A会向整个集群发起选举投票,它会先投自己一票,然后告诉B、C 大选开始了!

注意!只有candidate状态的节点,才可以参加竞选变为leader,B、C这两个follower是没有资格的!

除此之外,每个节点中还有一个字段,叫term意思就是任期,和美国大选的第几期总统差不多一个意思,这个term是一个全局的、连续递增的整数,每进行一次选举,term就会加一,如果candidate赢得选举,它会当leader直到此次任期结束。

此时,A触发了选举,它的term应该是加一的。

当B、C收到A发出的大选消息后,B、C开始投票,此时只有A这一个candidate,所以理所当然发消息都只能投A。

此时A当选leader!

为了巩固自己的“统治”,防止A在任期之间其他节点因为自身election timout而触发选举,leader节点A会不定时的向两个follower节点B、C发送心跳消息,B和C收到心跳消息后,会重置election timout。心跳检测时间很短,要远远小于选举超时时间election timout。

B、C收到心跳检测后,返回心跳响应,并重置超时时间election timeout。

假设A发送的心跳检测消息由于网络原因例如延迟、丢包等等没有传送到B、C中的某个Follower节点,而此时这个节点刚好election timeout,则触发选举。

C修改自身节点任期值term为2,自身状态变为candidate,且投自身一票后,发起选举!

这时候,由于C的任期值term变为2大于A的,在raft协议中,但收到任期值大于自身的节点,都会更改自身节点的term值,并切换为Follower状态并重置election time。

因此,这时候A由leader直接变为Follower!

我们再来考虑一种极端情况:假设有偶数个节点,并且同时有两个节点进入candiate状态!

例如有以下四个节点A、B、C、D。A和B同时进入了cadidate状态并开始选举。

假如A和B中任意一个获得了超过半数以上的多数票,则变为leader!

但是假如两个经过一次选举后得的票数相同或者都没有超过半数,则宣告选举失败并结束!等待A和C这两个candidate节点中任意一个节点的election time超时,然后发起新一轮选举。

注意:虽然票数相同或者都没有超过半数导致的选举失败了,但是任期值term还是要叠加的!

A、B票数相同,等待哪个先超时。

此时A先超时。则A发起选举,由于Aterm值显然是最大的,则A会最终当选为leader。

日志复制

当leader选出来后,无论读和写都会由leader节点来处理。

是的,读也由leader来处理,leader拿到请求后,再决定由哪一个节点来处理,要么将请求分发,要么自己处理;即使client端请求的是follower节点,Follower节点也会现将请求信息转给leader,再由leader决定由哪个节点来处理。

下面来说说写的情况:

以下有A、B、C三个节点,其中A是leader节点

当client请求过来要求写操作的时候,leader A先把数据写在本身节点的log文件中

然后A将发append entries消息发送给B、C节点。

注意!append entries消息其实是根据节点的不同而消息也不同的,因为集群中数据可能不一致,一味的传相同数据,显然不可以。具体怎么不一致,稍后再说。

B、C再收到消息后,把数据添加到本地,然后向A发消息,告诉A已经收到。

leaderA收到后,先提交记录,然后返回客户端响应。

然后,leaderA继续向B、C两个follower发送写数据commit的通知。

B、C两个节点收到通知后,先commit自身的log数据,然后再通知leaderA已更新结束。

到此整个数据同步也就结束了。

每次写数据,都需要先更新,然后commit。每个节点中都有两个索引,一个是当前提交的索引值commitIndex,一个是目前数据的最后一行索引值lastApplied。

而leader节点中,除了需要存储自身节点的commitIndex和lastApplied之外,还需要知道所有Follower的存储情况,因而leader节点中多了一张表,这张表中记录了所有follower节点的存储情况,这张表中有两个属性,一个属性叫nextIndex记录的是Follower节点没有的数据索引,需要发送append entries的数据索引;还有一个matchIndex记录的是leader节点已知的,follower节点的数据。如下图所示:

因此,当数据更新的时候,leaderA 向节点B、C发送不同的append entries。

当A节点不再当leader时,其他节点并不能知道leaderA保存的matchIndex和nextIndex这两个数组的数据。当其他节点成功当选为leader节点后,会将nextIndex全部重置为自身的commitIndex,而matchIndex则全部重置为0。如下图:

则,leaderB会向A和C节点发append entries,去"补全"数据

节点收到请求后,如果存在数据,就不动直接返回,如果没有数据则缺哪个补哪个。

总结

  • 触发选举的唯一条件是election timeout,心跳超时等其他条件仅仅是触发了非leader节点的election timeout。
  • 节点选举的时候,term值大的一定会力压term值小的当选leader。
  • leader节点向follower节点中发送append entries的时候,并不是缺少1、2、3就直接发送1、2、3而是分批次,一次发送一条。1! 2! 3!三条数据,分三次发完。(怕图片误导,特此说明!)

更多精彩内容,请关注我的微信公众号 互联网技术窝 或者加微信共同探讨交流:

 
 
 

手绘raft算法的更多相关文章

  1. 你也可以手绘二维码(二)纠错码字算法:数论基础及伽罗瓦域GF(2^8)

    摘要:本文讲解二维码纠错码字生成使用到的数学数论基础知识,伽罗瓦域(Galois Field)GF(2^8),这是手绘二维码填格子理论基础,不想深究可以直接跳过.同时数论基础也是 Hash 算法,RS ...

  2. JointBoost+CRF+GraphCut做手绘草图的分割

    研究生做的稍微有点水平的就这两个项目了:一个是利用SVM做手绘草图的分类,另一个是利用JointBoost+CRF做手绘草图的分割.总结得出的经验是做研究的方法就是将别人大神的代码看懂然后改成适合自己 ...

  3. UWP 手绘视频创作工具技术分享系列 - 有 AI 的手绘视频

    AI(Artificial Intelligence)正在不断的改变着各个行业的形态和人们的生活方式,图像识别.语音识别.自然语言理解等 AI 技术正在自动驾驶.智能机器人.人脸识别.智能助理等领域中 ...

  4. UWP 手绘视频创作工具技术分享系列 - 文字的解析和绘制

    本篇作为技术分享系列的第二篇,详细讲一下文字的解析和绘制,这部分功能的研究和最终实现由团队共同完成,目前还在寻找更理想的实现方式. 首先看一下文字绘制在手绘视频中的应用场景 文字是手绘视频中很重要的表 ...

  5. Microsoft Tech Summit 2018 课程简述:利用 Windows 新特性开发出更好的手绘视频应用

    概述 Microsoft Tech Summit 2018 微软技术暨生态大会将于10月24日至27日在上海世博中心举行,这也会是国内举办的最后一届 Tech Summit,2019 年开始会以 Mi ...

  6. Android基于mAppWidget实现手绘地图(一)--简介

    http://lemberg.github.io/mappwidget/user_guide.html 最近在看一些导游类应用,发现一些景区的导览图使用的完全是自定义地图,也就是手绘地图.这种小范围使 ...

  7. EDIUS手绘遮罩功能如何用

    学了这么久的EDIUS视频编辑软件,你们学的怎么样了呢?你们知道EIDUS手绘遮罩的用法么,会熟练地使用它么?如果你们还没有学到这一知识点的话也不要着急,因为你们看完下面这篇文章就会明白了.事不宜迟, ...

  8. 免费下载:320+ 手绘风格 Apple iOS7 图标

    Themify 图标是一套用在网页设计和应用程序的图标,包括 320+ 手工制作的像素完美的苹果  iOS7 图标中汲取灵感.这些图标完全免费,您可以用于任何目的,无论是个人或商业. 您可能感兴趣的相 ...

  9. IOS 手绘地图导航

    手绘地图导航 第三方库 NAMapKit, 1)支持在手绘图上标记.缩放 2)支持在单张图片 3)支持瓦片小图片 思路 前提:美工已经切好手绘图,并告知我们当前的缩放级别. 1)确定好手绘图左上角点在 ...

随机推荐

  1. B树与B+ 树

    本文转载自:http://www.cnblogs.com/yangecnu/p/Introduce-B-Tree-and-B-Plus-Tree.html 维基百科对B树的定义为“在计算机科学中,B树 ...

  2. 74.纯 CSS 创作一台 MacBook Pro

    原文地址:https://segmentfault.com/a/1190000015568609 HTML code: <div class="macbook"> &l ...

  3. 开窗函数over

    select   id,sum(je) over() as je from dt

  4. pyqt-QGrapicsView类

    QGrapicsView类 QGraphicsView提供一个显示QGraphicsScene内容的窗口,该窗口可以滚动,可以在构造时候把场景对象作为参数,或者之后使用setScene()来设置vie ...

  5. gitlab api 使用

    api文档:https://docs.gitlab.com/ee/api/projects.html#project-visibility-level 1.项目查询 http://127.0.0.1: ...

  6. 机器学习-Sklearn

    Scikit learn 也简称 sklearn, 是机器学习领域当中最知名的 python 模块之一. Sklearn 包含了很多种机器学习的方式: Classification 分类 Regres ...

  7. python中的全局变量和局部变量

    python中,对于变量作用域的规定有些不一样. 在诸如C/C++.java等编程语言中,默认在函数的内部是能够直接訪问在函数外定义的全局变量的,可是这一点在python中就会有问题.以下是一个样例. ...

  8. idea 设置光标回到上一次位置的快捷键

    1. file-->settings,搜索 navigate 这个 蓝色的back和forward分别就是光标后退.前进的快捷键了,全部移除原来冲突的快捷键,然后重新设置成自己的快捷键即可. 然 ...

  9. kinect 深度图与彩色图对齐程序

    //#include "duiqi.hpp" #include "kinect.h" #include <iostream> #include &q ...

  10. binlog2sql实现MySQL误操作的恢复

    对于MySQL数据库中的误操作删除数据的恢复问题,可以使用基于MySQL中binlog做到类似于闪回或者生成反向操作的SQL语句来实现,是MySQL中一个非常实用的功能.原理不难理解,基于MySQL的 ...