RocketMQ 多副本前置篇:初探raft协议

Raft协议是分布式领域解决一致性的又一著名协议,主要包含Leader选举、日志复制两个部分。服务器

舒适提示: 本文根据raft官方给出的raft动画进行学习,其动画展现地址:http://thesecretlivesofdata.com/raft/网络

一、Leader选举

1.1 一轮投票中,只有一个节点发起投票的状况

在这里插入图片描述

Raft协议中节点有3种状态(角色):分布式

  • Follower 跟随者。
  • Candidate 候选者。
  • Leader 领导者(Leader),一般咱们所说的的主节点。

首先3个节点初始状态为 Follower,每一个节点会有一个超时时间(计时器),其时间设置为150ms~300ms之间的随机值。当计时器到期后,节点状态从 Follower 变成 Candidate,以下图所示:源码分析

在这里插入图片描述

一般状况下,三个节点中会有一个节点的计时器率先到期,节点状态变为 Candidate ,候选者状态下的节点会发起选举投票。咱们先来考虑只有一个节点变为Candidate时是如何进行选主的。学习

当节点状态为Candidate,将发起一轮投票,因为是第一轮投票,设置本轮投票轮次为1,并首先为本身投上一票,正如上图所示的NodeA节点,Team为1,Vote Count为1. 在这里插入图片描述动画

当一个节点的定时器超时后,首先为本身投上一票,而后向该组内其余的节点发起投票(用拉票更加合适),发送投票请求。 在这里插入图片描述3d

当集群内的节点收到投票请求外,若是本轮未进行过投票,则赞同,不然反对,而后将结果返回,并重置计时器。 在这里插入图片描述日志

当节点A收到的赞同票大于一半时,则升级为该集群的 Leader,而后定时向集群内的其余节点发送心跳,以便肯定本身的领导地位,正以下图所示。 在这里插入图片描述中间件

Node A,集群中的 Leader正在向其余节点发送心跳包。 在这里插入图片描述blog

节点在收到 Leader 的心跳包后,返回响应结果,并重置自身的计时器,若是 Flower 状态的节点在计时时间超时内没有收到Leader 的心跳包,就会从 Flower 节点变成 Candidate,该节点就会发起下一轮投票。

例如NodeA节点宕机,中止向它的从发送心跳,咱们来看一下集群如何从新选主。 在这里插入图片描述

若是主节点宕机,则中止向集群内的节点发送心跳包。随着计时器的到期,节点B的先于节点C变成 Candidate,则节点B向集群内的其余节点发起投票,以下图所示。 在这里插入图片描述

节点B,首先将投票轮次设置为2,而后首先为本身投上一篇,而后向其余节点发起投票请求。 在这里插入图片描述

节点C收到请求,因为其投票轮次大于本身的投票轮次,并该轮次并未投票,投出同意票并返回结果,而后重置计时器。节点B将瓜熟蒂落的成为新的Leader并定时发送心跳包。

3个节点的选主就介绍到这里了,也许有网友会说,虽然各个节点的计时器是随机的,但也有可能同一时间,或一个节点在未收到另外一个节点发起的投票请求以前变成 Candidate,即在一轮投票过程当中,有大于1个的节点状态都是 Candidate,那该如何选主呢?

下面以4个节点的集群为例,来阐述上述这种状况状况下,如何进行选主。

1.2 一轮投票中,超过一个节点发起投票的状况

首先同时有两个节点进入Candidate状态,并开始新的一轮投票,当前投票编号为4,首先先为本身投上一票,而后向集群中的其余节点发起投票,以下图所示: 在这里插入图片描述

而后各个节点收到投票请求,以下所示,进行投票: 在这里插入图片描述

首先节点C、D在收到D、C节点的投票请求时,都会返回不一样意,由于在本轮投票中,已经各自为本身投了一票,按照上图,节点A赞成C节点、节点B赞成D节点,那此时C、D都只获的两票,固然若是A,B都认为C或D成为主节点,则选择就能够结束了,上图显示,C、D都只获的2票,未超过半数,没法成为主节点,那接下来会发生什么呢?请看下图: 在这里插入图片描述

此时A,B,C,D的定时器各自在倒计时,当节点成为Candidate时,或自身状态自己是Candidate而且定时器触发后,发起一轮新的投票,图中是节点B、节点D同时发起了新的一轮投票。 在这里插入图片描述

投票结果以下:节点A,节点C赞成节点B成为leader,但因为BD都发起了第5轮投票,最终的投票轮次更新为6,如图所示: 在这里插入图片描述

关于Raft协议的选主就介绍到这里了,接下来咱们来思考一下,若是本身实现 Raf t协议,至少要考虑哪些问题,为下一篇源码阅读Dleger(RocketMQ多副本)模块提供一些思路。

1.3 思考如何实现Raft选主

  1. 节点状态 须要引入3中节点状态:Follower(跟随者)、Candidate(候选者),投票的触发点,Leader(主节点)。
  2. 进入投票状态的计时器 Follower、Candidate 两个状态时,须要维护一个计时器,每次定时时间从150ms-300ms之间进行随机,即每一个节点的每次的计时过时不同,Follower状态时,计时器到点后,触发一轮投票。节点在收到投票请求、Leader 的心跳请求并做出响应后须要重置定时器。
  3. 投票轮次Team Candidate 状态的节点,每发起一轮投票,Term 加一;Term的存储。
  4. 投票机制 每一轮一个节点只能为一个节点投同意票,例如节点A中维护的轮次为3,而且已经为节点B投了同意票,若是收到其余节点,投票轮次为3,则会投反对票,若是收到轮次为4的节点,是又能够投同意票的。
  5. 成为Leader的条件 必须获得集群中节点的大多数,即超过半数,例如若是集群中有3个节点,则必须获得两票,若是其中一台服务器宕机,剩下的两个节点,还能进行选主吗?答案是能够的,由于能够获得2票,超过初始集群中3的一半,因此一般集群中的机器各位尽可能为计数,由于4台的可用性与3台的同样。

舒适提示:上述结论只是个人一些思考,咱们能够带着上述思考,进入到Dleger的学习中,下一篇将从源码分析的角度来学习大神是如何实现Raft协议的Leader选主的,让咱们一块儿期待吧。

二、日志复制

完成集群内的选主工做后,客户端向主节点发送请求,由主节点负责数据的复制,使集群内的数据保持一致性,初始状态以下图所示: 在这里插入图片描述

客户端向主节点发起请求,例如set 5,将数据更新为5,以下图所示: 在这里插入图片描述

主节点收到客户端请求后,将数据追加到Leader的日志中(但未提交),而后在下一个心跳包中将日志转发到集群内从节点,以下图所示: 在这里插入图片描述

从节点收到Leader的日志后,追加到从节点的日志文件中,并返回确认ACK。Leader收到从节点的确认信息后,向客户端发送确认信息。 在这里插入图片描述

上述的日志复制比较简单,是因为只考虑正常的状况,若是中间发生异常,该如何保证数据一致性呢?

  1. 若是 Leader 节点向从节点广播日志时,其中某个从节点发送故障宕机,该如何处理呢?
  2. 日志在什么环节进行提交呢?Leader节点在收到客户端的数据变动请求后,首先追加到主节点的日志文件中,而后广播到从节点,从节点收到日志信息,是提交日志后返回ACK,仍是何时提交呢?
  3. 日志如何保证惟一。
  4. 如何处理网络出现分区。

我相信读者朋友确定还有更多的疑问,本文不打算来回答上述疑问,而是带着这些问题进入到RocketMQ多副本的学习中,经过源码分析RocketMQ DLedger的实现后,再来从新总结raft协议。

亲爱的读者们,读到这里了,烦请点个赞,谢谢,下一篇将重点分析RocketMQ Dledger 多副本模块如何实现 raft 协议的选主。


做者简介:《RocketMQ技术内幕》做者,RocketMQ 社区布道师,维护公众号:中间件兴趣圈,可扫描以下二维码与做者进行互动。

相关文章
相关标签/搜索