实现 Raft 协议
简介
Raft 是一个分布式共识算法,用于保证所有机器对一件事达成一个看法。本文用于记录实现 Raft 选举和日志复制的代码细节。
选举
节点启动时首先是跟随者状态,如果到达选举超时时间就尝试选举,为了预防对称网络分区带来的任期不断增加问题,需要使用预投票机制。
选举超时时间:跟随者在这段时间内没有搜到领导者的消息,就触发选举超时,转变为候选者开始竞选
对称网络分区:以 3 台机器为例,其中一台机器与另外两台机器(这两台中有一个领导者)的网络隔离开了,此时跟随者会触发选举超时,导致其不断增加任期,在网络恢复正常时,领导者会因任期小而下线,集群因此触发重新选举
预投票机制:触发选举超时先询问其他节点是否同意当前节点进行投票,当多数节点同意时再进行投票,即正式投票
上面介绍了选举需要注意的问题,下面说具体流程。
- 节点启动时开启一个选举超时时间检测定时任务,用于在当前节点是跟随者时不断检测是否发生了选举超时,发生超时就开始竞选。每一次定时任务的触发时间都是变化的,以防止所有节点一起选举,所有人都不投票后死循环。
- 任务内容:如果当前节点不是跟随者或选举超时时间内收到了来自领导者的消息就跳过这轮检测,否则就代表领导者可能下线了,开始竞选。
- 竞选的第一阶段是预投票:发起预投票 RPC,内容有想竞选的任期以及当前的最新日志的任期和索引,如果只有少数节点同意投票就结束这轮任务,否则开始正式投票,RPC 内容与上次相同,但这次需要改变当前节点任期号为想竞选的任期号了,同时也要更改状态为候选者,如果只有少数节点同意投票就结束这轮任务(同时回滚状态为跟随者),否则就更改状态成为领导者,开始发送心跳等等(成为领导者的一些事后面再说)。
到这里跟随者如何选举成为候选者以及领导者就大致完成了,还缺少其他节点如何处理投票请求:
- 请求的任期比当前节点小就拒绝。
- 领导者有效(选举超时时间内有收到了心跳)就拒接。
- 该任期已经投过票就拒绝。
- 最新的本地日志任期大就拒绝,日志任期相同但本地最新日志的索引更大也拒绝。
如果上面 4 个条件全通过就投票。投票过程中还有一些节点状态的变更处理,比如收到正式投票的任期比当前节点任期大需要转变为跟随者等等,当前这些也不是重点。
日志复制
日志复制是 Raft 的核心,这里涉及到状态机的执行,也就是共识的关键,比较复杂。
在完成选举后集群有了领导者,由领导者负责与客户端沟通,在领导者收到客户端请求时,领导者将这条待状态机执行的命令和当前任期组合成一条日志写入本地磁盘,并向其他节点发送该条日志,如果多数节点都表示收到了,也就表明达成共识了,那么领导者就会将这个命令放到状态机中执行,那么什么时候集群中的其他跟随者节点的状态机执行该条日志的命令呢?答案是由定时的心跳负责,每次心跳都会携带领导者状态机最后执行的日志索引,当跟随者收到后就会将当前节点状态机最后执行的日志索引和心跳中领导者的日志索引之间的日志放到状态机中执行,也就是说日志中命令的执行是一个二阶段的过程。
选举中我们忽略了一个地方,就是成为领导者后需要询问集群的节点日志复制情况,以此来将当前领导者多的日志复制到其他跟随者,大概过程如下:领导者拿着最新日志的任期和索引和跟随者对比,如果相同,等着领导者新的日志复制就行了,如果不同,说明这个日志是脏的(日志没被复制给大多数),此时领导者拿着该条日志的前一条日志继续对比,直到相同,然后领导者将相同的日志之后的所有日志复制给跟随者,跟随者将相同日志后的日志都删掉,再追加上领导者发来的日志,这样跟随者的日志就正确了。跟随者与领导者日志的对齐后就可以等待领导者发心跳了(即通知跟随者将哪些日志放到状态机中执行)。
关于状态机执行日志还有很重要的一点,就是节点需不需要保存当前状态机执行过的最后一条日志的索引,比如机器重启了,从头执行所有日志对状态机有没有影响。可以思考下,如果是一个 KV 数据库状态机,不保存也没问题,因为日志不管从哪里执行,数据库中的数据也不会变,但如果是 id 生成器,就会出现多执行一次 id 就会变化,多执行很多次甚至可能出现 id 分配完无法继续分配的问题,所以命令执行多次有问题就需要保存,并且需要满足保存执行过的索引和执行状态机命令是一个原子性的操作。
读请求优化(读索引读)
日志复制是需要刷盘的,这个操作非常耗时,写请求只能通过领导者进行日志复制处理,但读请求不同,可以像 ReentrantReadWriteLock 读写锁一样,将读请求负载到跟随者上,也就是实现跨机器的 volatile 语义(和跨进程类似),即读跟随者时确保跟随者的状态机已经和领导者的状态机一样,具体过程如下:跟随者收到读请求,跟随者请求领导者同步日志以及状态机应该执行到那条日志,领导者收到请求后向所有的节点发一个 RPC 确认领导者地位(防止领导者所在的少部分节点分区后还能正常读),确认后同步日志并回复该跟随者,收到回复后的跟随者的状态机再执行读请求。
对于领导者的读请求同样也不需要走日志复制,只需要和其他跟随者确认自己的领导者地位就可以执行读命令了。
最后
coding 时要注意节点任期的变化,刚开始可以先用一个全局锁来回避这个问题,等后面到一定的复杂程度再细化锁。完整的 Raft 还需要考虑很多,比如快照、批量、pipeline、删减节点等等。最后贴上我的实现 raft/README.md 以及相关学习资料:
为什么 Raft 的 ApplyIndex 和 CommitIndex 不需要持久化? - 知乎 (zhihu.com)
stateIs0/lu-raft-kv: this is raft java project. raft-kv-storage (github.com)
wenweihu86/raft-java: Raft Java implementation which is simple and easy to understand. (github.com)
实现 Raft 协议的更多相关文章
- Raft协议实战之Redis Sentinel的选举Leader源码解析
这可能是我看过的写的最详细的关于redis 选举的文章了, 原文链接 Raft协议是用来解决分布式系统一致性问题的协议,在很长一段时间,Paxos被认为是解决分布式系统一致性的代名词.但是Paxos难 ...
- MIT-6.824 Raft协议
摘要 raft是一种比paxos容易理解的一致性算法,实现起来比paxos简单许多.本文前部分描述算法的细节,后部分尝试探讨下该算法的原理. 算法描述 raft算法之所以简单的原因之一是它将问题分解成 ...
- Raft协议学习笔记
目录 目录 1 1. 前言 1 2. 名词 1 3. 什么是分布式一致性? 3 4. Raft选举 3 4.1. 什么是Leader选举? 3 4.2. 选举的实现 4 4.3. Term和Lease ...
- [搜狐科技]由浅入深理解Raft协议
由浅入深理解Raft协议 2017-10-16 12:12操作系统/设计 0 - Raft协议和Paxos的因缘 读过Raft论文<In Search of an Understandable ...
- Paxos、ZAB、RAFT协议
这三个都是分布式一致性协议,ZAB基于Paxos修改后用于ZOOKEEPER协议,RAFT协议出现在ZAB协议之后,与ZAB差不多,也有很大区别. 1. Paxos 分布式节点分为3种角色, Prop ...
- Paxos算法与Zookeeper分析,zab (zk)raft协议(etcd) 8. 与Galera及MySQL Group replication的比较
mit 分布式论文集 https://github.com/feixiao/Distributed-Systems wiki上描述的几种都明白了就出师了 raft 和 zab 是类似的,都是1.先选举 ...
- RocketMQ 多副本前置篇:初探raft协议
目录 1.Leader选举 1.1 一轮投票中,只有一个节点发起投票的情况 1.2 一轮投票中,超过一个节点发起投票的情况 1.3 思考如何实现Raft选主 2.日志复制 Raft协议是分布式领域解决 ...
- 基于 raft 协议的 RocketMQ DLedger 多副本日志复制设计原理
目录 1.RocketMQ DLedger 多副本日志复制流程图 1.1 RocketMQ DLedger 日志转发(append) 请求流程图 1.2 RocketMQ DLedger 日志仲裁流程 ...
- raft协议-分布式环境下的数据一致性问题
阅读了一个有意思的ppt,是Standford大学发表的raft协议 网址:http://thesecretlivesofdata.com/raft/ 下面自己总结下咯: 1.raft是一个实现了解决 ...
- DLedger —基于 raft 协议的 commitlog 存储库
“点击获取上云帮助文档” 尊敬的阿里云用户: 您好!为方便您试用开源 RocketMQ 客户端访问阿里云MQ,我们申请了专门的优惠券,优惠券可以直接抵扣金额.请填写下您公司账号信息,点击上图,了解更多 ...
随机推荐
- ECharts图表动态修改series显示隐藏
目录 1.前言 2.思路 3.实现 1.前言 最近做的大数据平台,里面很多地方用到了ECharts,其中有个功能,要求将图表分组,根据用户选择的组,来确定ECharts要显示那些线条和柱子,也就是动态 ...
- OpenLDAP服务器搭建
一.关闭防火墙和selinux [root@localhost ~]# systemctl stop firewalld.service [root@localhost ~]# systemctl d ...
- [TSG开发日志](一)软件基础框架
目录 前言 说明 框架 TSG_Framework 一.底层信号机制 TSG_Caller 二.参数类型声明 TSG_Params 三.设备类声明 TSG_Device 四.设备配置文件控制 TSG_ ...
- Kali-Linux-配置开发环境
本文主要讲解JDK.SDK.eclipse-adt.android studio.cpu模式TensorFlow 的安装配置.update:2019-08-30 03:31:46 JDK 当前系统jd ...
- C#结合OpenCVSharp4图片相似度识别
OpenCVSharp4图片相似度识别 需求背景:需要计算两个图片的相似度,然后将相似的图片进行归纳 1. 图片相似度算法 由于我是CRUD后端仔,对图像处理没什么概念.因此网上调研了几种相似度算法分 ...
- 【matplotlib基础】--几何图形
除了绘制各类分析图形(比如柱状图,折线图,饼图等等)以外,matplotlib 也可以在画布上任意绘制各类几何图形.这对于计算机图形学.几何算法和计算机辅助设计等领域非常重要. matplitlib ...
- python实现简单的爬虫功能
前言Python是一种广泛应用于爬虫的高级编程语言,它提供了许多强大的库和框架,可以轻松地创建自己的爬虫程序.在本文中,我们将介绍如何使用Python实现简单的爬虫功能,并提供相关的代码实例. 如何实 ...
- 解密网络通信的关键技术(下):DNS、ARP、DHCP和NAT,你了解多少?
引言 在上一章中,我们详细介绍了域名系统(DNS)和地址解析协议(ARP)的工作原理,从而对域名解析和介质访问控制(MAC)地址寻址有了更深入的了解.在今天的章节中,我们将继续探讨动态主机配置协议(D ...
- Merge-Lrc 合并歌词的小工具
Merge-Lrc 背景 音乐区有群友希望各种乱七八糟的歌词(lrc 格式居多,里面甚至还有翻译)可以整理成单一的文件,或者一个仅翻译的歌词可以和原文的歌词合并.于是就开发了这款工具.地址:https ...
- 在 Linux 环境(Ubuntu)下安装 Slurm 和 OpenMPI
安装 Slurm 从软件源安装 slurm-wlm(每个节点都需要装的执行工具).slurm-client(客户机装的提交命令的工具).munge(节点间通信插件) sudo apt install ...