文章地址

简介

Raft 是一个分布式共识算法,用于保证所有机器对一件事达成一个看法。本文用于记录实现 Raft 选举和日志复制的代码细节。

选举

节点启动时首先是跟随者状态,如果到达选举超时时间就尝试选举,为了预防对称网络分区带来的任期不断增加问题,需要使用预投票机制。

选举超时时间:跟随者在这段时间内没有搜到领导者的消息,就触发选举超时,转变为候选者开始竞选

对称网络分区:以 3 台机器为例,其中一台机器与另外两台机器(这两台中有一个领导者)的网络隔离开了,此时跟随者会触发选举超时,导致其不断增加任期,在网络恢复正常时,领导者会因任期小而下线,集群因此触发重新选举

预投票机制:触发选举超时先询问其他节点是否同意当前节点进行投票,当多数节点同意时再进行投票,即正式投票

上面介绍了选举需要注意的问题,下面说具体流程。

  1. 节点启动时开启一个选举超时时间检测定时任务,用于在当前节点是跟随者时不断检测是否发生了选举超时,发生超时就开始竞选。每一次定时任务的触发时间都是变化的,以防止所有节点一起选举,所有人都不投票后死循环。
  2. 任务内容:如果当前节点不是跟随者或选举超时时间内收到了来自领导者的消息就跳过这轮检测,否则就代表领导者可能下线了,开始竞选。
  3. 竞选的第一阶段是预投票:发起预投票 RPC,内容有想竞选的任期以及当前的最新日志的任期和索引,如果只有少数节点同意投票就结束这轮任务,否则开始正式投票,RPC 内容与上次相同,但这次需要改变当前节点任期号为想竞选的任期号了,同时也要更改状态为候选者,如果只有少数节点同意投票就结束这轮任务(同时回滚状态为跟随者),否则就更改状态成为领导者,开始发送心跳等等(成为领导者的一些事后面再说)。

到这里跟随者如何选举成为候选者以及领导者就大致完成了,还缺少其他节点如何处理投票请求:

  1. 请求的任期比当前节点小就拒绝。
  2. 领导者有效(选举超时时间内有收到了心跳)就拒接。
  3. 该任期已经投过票就拒绝。
  4. 最新的本地日志任期大就拒绝,日志任期相同但本地最新日志的索引更大也拒绝。

如果上面 4 个条件全通过就投票。投票过程中还有一些节点状态的变更处理,比如收到正式投票的任期比当前节点任期大需要转变为跟随者等等,当前这些也不是重点。

日志复制

日志复制是 Raft 的核心,这里涉及到状态机的执行,也就是共识的关键,比较复杂。

在完成选举后集群有了领导者,由领导者负责与客户端沟通,在领导者收到客户端请求时,领导者将这条待状态机执行的命令和当前任期组合成一条日志写入本地磁盘,并向其他节点发送该条日志,如果多数节点都表示收到了,也就表明达成共识了,那么领导者就会将这个命令放到状态机中执行,那么什么时候集群中的其他跟随者节点的状态机执行该条日志的命令呢?答案是由定时的心跳负责,每次心跳都会携带领导者状态机最后执行的日志索引,当跟随者收到后就会将当前节点状态机最后执行的日志索引和心跳中领导者的日志索引之间的日志放到状态机中执行,也就是说日志中命令的执行是一个二阶段的过程。

选举中我们忽略了一个地方,就是成为领导者后需要询问集群的节点日志复制情况,以此来将当前领导者多的日志复制到其他跟随者,大概过程如下:领导者拿着最新日志的任期和索引和跟随者对比,如果相同,等着领导者新的日志复制就行了,如果不同,说明这个日志是脏的(日志没被复制给大多数),此时领导者拿着该条日志的前一条日志继续对比,直到相同,然后领导者将相同的日志之后的所有日志复制给跟随者,跟随者将相同日志后的日志都删掉,再追加上领导者发来的日志,这样跟随者的日志就正确了。跟随者与领导者日志的对齐后就可以等待领导者发心跳了(即通知跟随者将哪些日志放到状态机中执行)。

关于状态机执行日志还有很重要的一点,就是节点需不需要保存当前状态机执行过的最后一条日志的索引,比如机器重启了,从头执行所有日志对状态机有没有影响。可以思考下,如果是一个 KV 数据库状态机,不保存也没问题,因为日志不管从哪里执行,数据库中的数据也不会变,但如果是 id 生成器,就会出现多执行一次 id 就会变化,多执行很多次甚至可能出现 id 分配完无法继续分配的问题,所以命令执行多次有问题就需要保存,并且需要满足保存执行过的索引和执行状态机命令是一个原子性的操作。

读请求优化(读索引读)

日志复制是需要刷盘的,这个操作非常耗时,写请求只能通过领导者进行日志复制处理,但读请求不同,可以像 ReentrantReadWriteLock 读写锁一样,将读请求负载到跟随者上,也就是实现跨机器的 volatile 语义(和跨进程类似),即读跟随者时确保跟随者的状态机已经和领导者的状态机一样,具体过程如下:跟随者收到读请求,跟随者请求领导者同步日志以及状态机应该执行到那条日志,领导者收到请求后向所有的节点发一个 RPC 确认领导者地位(防止领导者所在的少部分节点分区后还能正常读),确认后同步日志并回复该跟随者,收到回复后的跟随者的状态机再执行读请求。

对于领导者的读请求同样也不需要走日志复制,只需要和其他跟随者确认自己的领导者地位就可以执行读命令了。

最后

coding 时要注意节点任期的变化,刚开始可以先用一个全局锁来回避这个问题,等后面到一定的复杂程度再细化锁。完整的 Raft 还需要考虑很多,比如快照、批量、pipeline、删减节点等等。最后贴上我的实现 raft/README.md 以及相关学习资料:

实现 Raft 协议的更多相关文章

  1. Raft协议实战之Redis Sentinel的选举Leader源码解析

    这可能是我看过的写的最详细的关于redis 选举的文章了, 原文链接 Raft协议是用来解决分布式系统一致性问题的协议,在很长一段时间,Paxos被认为是解决分布式系统一致性的代名词.但是Paxos难 ...

  2. MIT-6.824 Raft协议

    摘要 raft是一种比paxos容易理解的一致性算法,实现起来比paxos简单许多.本文前部分描述算法的细节,后部分尝试探讨下该算法的原理. 算法描述 raft算法之所以简单的原因之一是它将问题分解成 ...

  3. Raft协议学习笔记

    目录 目录 1 1. 前言 1 2. 名词 1 3. 什么是分布式一致性? 3 4. Raft选举 3 4.1. 什么是Leader选举? 3 4.2. 选举的实现 4 4.3. Term和Lease ...

  4. [搜狐科技]由浅入深理解Raft协议

    由浅入深理解Raft协议 2017-10-16 12:12操作系统/设计 0 - Raft协议和Paxos的因缘 读过Raft论文<In Search of an Understandable ...

  5. Paxos、ZAB、RAFT协议

    这三个都是分布式一致性协议,ZAB基于Paxos修改后用于ZOOKEEPER协议,RAFT协议出现在ZAB协议之后,与ZAB差不多,也有很大区别. 1. Paxos 分布式节点分为3种角色, Prop ...

  6. Paxos算法与Zookeeper分析,zab (zk)raft协议(etcd) 8. 与Galera及MySQL Group replication的比较

    mit 分布式论文集 https://github.com/feixiao/Distributed-Systems wiki上描述的几种都明白了就出师了 raft 和 zab 是类似的,都是1.先选举 ...

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

    目录 1.Leader选举 1.1 一轮投票中,只有一个节点发起投票的情况 1.2 一轮投票中,超过一个节点发起投票的情况 1.3 思考如何实现Raft选主 2.日志复制 Raft协议是分布式领域解决 ...

  8. 基于 raft 协议的 RocketMQ DLedger 多副本日志复制设计原理

    目录 1.RocketMQ DLedger 多副本日志复制流程图 1.1 RocketMQ DLedger 日志转发(append) 请求流程图 1.2 RocketMQ DLedger 日志仲裁流程 ...

  9. raft协议-分布式环境下的数据一致性问题

    阅读了一个有意思的ppt,是Standford大学发表的raft协议 网址:http://thesecretlivesofdata.com/raft/ 下面自己总结下咯: 1.raft是一个实现了解决 ...

  10. DLedger —基于 raft 协议的 commitlog 存储库

    “点击获取上云帮助文档” 尊敬的阿里云用户: 您好!为方便您试用开源 RocketMQ 客户端访问阿里云MQ,我们申请了专门的优惠券,优惠券可以直接抵扣金额.请填写下您公司账号信息,点击上图,了解更多 ...

随机推荐

  1. 使用 Laf 一周内上线美术狮 AI 绘画小程序

    "美术狮 AI 绘画"(以下简称"美术狮"),是我们小团队的一次尝试,定位是人人都可以上手的,充满创意的,理解中文和中国文化的图片生成工具. 在完善图像模型和论 ...

  2. 这个 AI 机器人会怼人,它是怎么做到的?

    近期,机器人"Ameca"接入了 Stable Diffusion,它一边与旁边的人类工程师谈笑风生,一边熟练地用马克笔在白板上画出一只简笔的猫,最后还在白板右下角签名. 当 Am ...

  3. 浅谈API安全的应用

    ​ 理论基础 API它的全称是Application Programming Interface,也叫做应用程序接口,它定义了软件之间的数据交互方式.功能类型.随着互联网的普及和发展,API 从早期的 ...

  4. from itertools import groupby

    需求:期望由 a 得到 b 实现方法: from itertools import groupby a = [ {'name': 'a', 'value': 1}, {'name': 'b', 'va ...

  5. sublime运行php文件

    sublime 运行 php 文件 使用 sublime 打开一个php文件 然后 Tools -> Build System -> New Build System 将以上打开的文件内容 ...

  6. Content Security Policy(CSP)应用及说明

    什么是CSP CSP全称Content Security Policy ,可以直接翻译为内容安全策略,说白了,就是为了页面内容安全而制定的一系列防护策略. 通过CSP所约束的的规责指定可信的内容来源( ...

  7. Solution Set -「CF 1539」

    我是傻逼. 「CF 1539A」Contest Start Link. 答案是 \(\sum_{i=1}^{n-1}\min\{i,\lfloor\frac{t}{x}\rfloor\}\),等差数列 ...

  8. 【网络爬虫笔记】爬虫Robots协议语法详解

    Robots协议是指一个被称为Robots Exclusion Protocol的协议.该协议的主要功能是向网络蜘蛛.机器人等搜索引擎爬虫提供一个标准的访问控制机制,告诉它们哪些页面可以被抓取,哪些页 ...

  9. .NET周刊【9月第3期 2023-09-17】

    国内文章 在.NET 8 RC1 版本中 MAUI.ASP.NET Core 和 EF8 的新特性 https://www.cnblogs.com/shanyou/p/17698428.html 从年 ...

  10. OSPF路由 与 ISIS路由 与路由学习对比

    转载请注明出处: 1.OSPF 路由学习规律 OSPF使用链路状态数据库(Link State Database)来存储网络拓扑信息.每个OSPF路由器通过交换链路状态更新(Link State Up ...