详解共识算法的Raft算法模拟数
摘要:Raft算法是一种分布式共识算法,用于解决分布式系统中的一致性问题。
本文分享自华为云社区《共识算法之Raft算法模拟数》,作者: TiAmoZhang 。
01、Leader选举
存在A、B、C三个成员组成的Raft集群,刚启动时,每个成员都处于Follower状态,其中,成员A心跳超时为110ms,成员B心跳超时为150ms,成员C心跳超时为130ms,其他相关信息如图1所示。

■ 图1 Raft模拟初始状态
由于集群中不存在Leader,A、B、C三个成员都不会收到来自Leader的心跳信息。其中,成员A的超时最短,最先进入选举状态,修改自己的状态为Candidate,并增加自己的任期编号为1,发起请求投票消息,如图2所示。

■ 图2 请求投票
成员A通过RequestVote广播自己的选票给成员B、C,选票描述了成员A所拥有的数据,其包含成员A所处的term及最新的日志索引。成员B、C根据投票规则处理RequestVote消息。
term大的成员拒绝投票给term小的成员。
日志索引大的成员拒绝投票给日志索引小的成员。
一个term内只投出一张选票,采用先来先获得投票的原则。
很明显,成员B、C的term小于成员A的term,也不存在比成员A日志索引更大的日志索引,并且term为1的选票还没有投给其他成员,因此成员B、C将term为1的选票投给成员A并更新自己的term为1。
成员A获得包括自己在内的3张选票,赢得大多数选票,成员A晋升为Leader,并向其他成员发送心跳信息,维护自己的领导地位,如图3所示。

■ 图3 Leader晋升示意
如果成员A在等待投票超过约定的时间内没有收到多数派的选票,则会重置自己的超时,并结束本次选举进程。接着会有其他成员在等待心跳超时后发起Leader选举,在当前案例中,发起Leader选举的顺序为A→C→B。
可能因为网络问题,使集群中的所有成员又发起了一轮选举,但是都没有获得多数派的选票,因此会随机产生新的超时,开始下一个循环的选举。
02、日志复制
日志复制是一个一阶段协商的过程,其中,日志项的提交操作由下一轮协商或者心跳消息来代替完成。因此处理事务请求,Raft只需要发送一轮AppendEntries消息即可。
AppendEntries消息除了会包含需要复制日志项的相关信息外,通常会携带Leader的committedIndex参数,标示着最后一个已提交的日志索引。每个Follower的本地都维护了committedIndex,Follower可以对比Leader的committedIndex来推进自己的提交操作。
接着如图3所示的示例,一个三个成员组成的集群,成员A为Leader,成员B和C为Follower,并且在集群中未提交任何日志项。Leader收到客户端发送的Add请求后,Leader和Follower依次执行以下步骤,如图4所示。

■ 图4 日志复制-复制
(1)Leader将其封装成日志项追加到本地的日志中,日志索引为1。
(2)Leader通过AppendEntries(0, <1, Add>)消息时将日志项广播给所有的Follower。其中:
- 第一个参数为committedIndex,即Leader最后提交的日志索引。
- 第二个参数为Leader所处的日志索引,即Add日志项的索引。
- 第三个参数为事务操作指令,即客户端的指令。
(3)Follower收到消息,将日志项追加到本地的日志中。
此时,成员A、B、C都拥有日志项Add且都已在索引为1上完成了持久化。Follower在处理完AppendEntries消息后需要回复ACK消息给Leader,代表接受该日志项。Leader收到多数派的ACK消息后,可以在本地提交该日志项并执行状态转移,之后将执行结果返回给客户端,如图5所示。

■ 图5 日志复制-回复
在当前场景中,成员A提交了索引为1的日志项,成员B、C仅仅拥有索引为1的日志项的所有信息但并未提交。成员B、C需要等待下一次AppendEntries消息,根据其committedIndex推进索引为1的日志项的提交操作。以心跳的AppendEntries消息为例,该AppendEntries消息仅携带了committedIndex,此时Leader已经提交了索引为1的日志项,因此committedIndex为1。Follower则可以提交索引为1及其之前的所有日志项,如图6所示。

■ 图6 日志复制-心跳
03、日志对齐
我们使用<term, logIndex>表示一个日志项,如表1所示为Follower E的日志索引3和Follower D的日志索引4,与当前Leader处理不一致的情况。出现这种情况可能是Follower E和Follower D曾经当选过Leader,并且在自己的term上提出了日志索引为3和4的日志项后立即宕机造成的。
■ 表1 日志对齐

要使Follower E和Follower D与Leader数据保持一致,大致步骤分为两步:寻找nextIndex,复制nextIndex及其之后的日志项。在Raft中,这个步骤均可由AppendEntries消息来完成。这里以Follower E成员为例,交互细节如下:
(1)Leader为Follower E初始化nextIndex,nextIndex=lastLogIndex+1,即nextIndex=6+1=7。
(2)Leader通过AppendEntries发送探测消息,携带preLogIndex(nextIndex-1)及preLogTerm,其中,preLogIndex=6,preLogTerm=3。
(3)Follower收到探测消息,对比索引为6的日志项,返回失败的响应给Leader并携带lastLogIndex=3。
(4)Leader收到失败的响应,更新nextIndex=lastLogIndexmsg+1,即nextIndex=4。
(5)Leader发送下一轮的探测消息,其中,preLogIndex=3,preLogTerm=2。
(6)Follower收到探测消息,对比索引为3的日志项,返回失败的响应给Leader并携带lastLogIndex=3。
(7)Leader收到失败的响应,此时lastLogIndexmsg+1 ≤ nextIndex,则nextIndex单调递减为3。
(8)Leader发送下一轮的探测消息,其中,preLogIndex=2,preLogTerm=1。
(9)Follower收到探测消息,对比索引为2的日志项,返回探测成功的响应给Leader。
(10)Leader在成功探测到nextIndex之后,通过AppendEntries消息从nextIndex开始发送索引为3的日志项给Follower。
(11)Follower将以Leader的数据为准,覆盖本地的日志项并返回处理成功的响应给Leader。
(12)Leader收到成功响应后,单调递增nextIndex,继续发送下一个日志项。直到nextIndex等于Leader的lastLogIndex,意味着该Follower拥有Leader所有的数据,本次日志对齐即完成。
详解共识算法的Raft算法模拟数的更多相关文章
- 分布式共识算法 (三) Raft算法
系列目录 分布式共识算法 (一) 背景 分布式共识算法 (二) Paxos算法 分布式共识算法 (三) Raft算法 分布式共识算法 (四) BTF算法 一.引子 1.1 介绍 Raft 是一种为了管 ...
- 分布式一致性算法:Raft 算法(论文翻译)
Raft 算法是可以用来替代 Paxos 算法的分布式一致性算法,而且 raft 算法比 Paxos 算法更易懂且更容易实现.本文对 raft 论文进行翻译,希望能有助于读者更方便地理解 raft 的 ...
- 【转】分布式一致性算法:Raft 算法(Raft 论文翻译)
编者按:这篇文章来自简书的一个位博主Jeffbond,读了好几遍,翻译的质量比较高,原文链接:分布式一致性算法:Raft 算法(Raft 论文翻译),版权一切归原译者. 同时,第6部分的集群成员变更读 ...
- 详解 volatile关键字 与 CAS算法
(请观看本人博文 -- <详解 多线程>) 目录 内存可见性问题 volatile关键字 CAS算法: 扩展 -- 乐观锁 与 悲观锁: 悲观锁: 乐观锁: 在讲解本篇博文的知识点之前,本 ...
- 详解十大经典数据挖掘算法之——Apriori
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是机器学习专题的第19篇文章,我们来看经典的Apriori算法. Apriori算法号称是十大数据挖掘算法之一,在大数据时代威风无两,哪 ...
- 详解十大经典机器学习算法——EM算法
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是机器学习专题的第14篇文章,我们来聊聊大名鼎鼎的EM算法. EM算法的英文全称是Expectation-maximization al ...
- Redis中算法之——Raft算法
Sentinel系统选举领头的方法是对Raft算法的领头选举方法的实现. 在分布式系统中一致性是很重要的.1990年Leslie Lamport提出基于消息传递的一致性算法Paxos算法,解决分布式系 ...
- 详解BarTender符号体系特殊选项之“行数”
上面两篇文章小编和大家分享了BarTender符号体系特殊选项中的“行高”和“列”.此外,某些二维 (2D) 符号体系的结构为多个信息行,每一行看上去都像一个非常窄的条形码. 例如,以下图像是含 3 ...
- ulimit 命令详解 socket查看linux最大文件打开数
ulimit 命令详解 Linux对于每个用户,系统限制其最大进程数.为提高性能,可以根据设备资源情况,设置各linux 用户的最大进程数 可以用ulimit -a 来显示当前的各种用户进程限 ...
- Lua5.4源码剖析:二. 详解String数据结构及操作算法
概述 lua字符串通过操作算法和内存管理,有以下优点: 节省内存. 字符串比较效率高.(比较哈希值) 问题: 相同的字符串共享同一份内存么? 相同的长字符串一定不共享同一份内存么? lua字符串如何管 ...
随机推荐
- Java Stream常见用法汇总,开发效率大幅提升
本文已经收录到Github仓库,该仓库包含计算机基础.Java基础.多线程.JVM.数据库.Redis.Spring.Mybatis.SpringMVC.SpringBoot.分布式.微服务.设计模式 ...
- 关于Java中代码的执行顺序
结论 注意 只有显式的加载类 JVM才会加载到内存中 先加载父类的静态代码块 然后执行子类静态代码块 当前类存在类静态变量注意引用类型没进行赋值操作初始化为null 并不会显式的加载类又存在静态代码块 ...
- Windows防病毒Defender 排除病毒误报
开发的软件安装后,windows上提示病毒,默默被系统删除了. 一开始以为是自己软件的签名问题,后面发现,将被隔离的文件还原,文件的签名是存在的. 这是微软denfender的误报,为啥会报病毒呢? ...
- SSM之简单的CRUD
文章目录 前言 项目介绍 项目代码介绍 数据库文件 源码介绍 代码展示 配置文件 业务逻辑代码 总结 前言 大家好呀,前面不是说最近在学习SSM么,可能学的不是那么深,不过刚刚开始,学完肯定需要先动手 ...
- python的format方法中文字符输出问题
format方法的介绍 前言 提示:本文仅介绍format方法的使用和中文的输出向左右和居中输出问题 一.format方法的使用 format方法一般可以解决中文居中输出问题,假如我们设定宽度,当中文 ...
- 一文搞懂 x64 IA-64 AMD64 Inte64 IA-32e 架构之间的关系
想要搞清楚 x64.IA64.AMD64 指令集之间的关系,就要先了解 Intel 和 AMD 这两家公司在生产处理器上的发展历史. x86 处理器 1978年 Intel 生产了它的第一款 16bi ...
- PBN衔接ILS时中间进近航段的保护区绘制方法
收到网友提问,PBN程序和ILS程序在衔接时,中间进近航段的保护区该怎么去绘制. 这个问题怎么看呢?首先起始进近航段与中间进近航段存在两种连接方式,一种是直线进近.另一种是转弯进近,两者的保护区是显著 ...
- 2022-07-13:给你一个整数数组 arr ,你一开始在数组的第一个元素处(下标为 0)。 每一步,你可以从下标 i 跳到下标 i + 1 、i - 1 或者 j : i + 1 需满足:i +
2022-07-13:给你一个整数数组 arr ,你一开始在数组的第一个元素处(下标为 0). 每一步,你可以从下标 i 跳到下标 i + 1 .i - 1 或者 j : i + 1 需满足:i + ...
- Netty实战(一)
目录 第一章 Java网络编程 1.1 Java NIO 1.2 选择器 第二章 Netty是什么 2.1 Netty简介 2.2 Netty的特性 2.2.1 设计 2.2.2 易于使用 2.2.3 ...
- go语言中如何实现同步操作呢
1. 简介 本文探讨了并发编程中的同步操作,讲述了为何需要同步以及两种常见的实现方式:sync.Cond和通道.通过比较它们的适用场景,读者可以更好地了解何时选择使用不同的同步方式.本文旨在帮助读者理 ...