Raft 一致性算法

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Raft 一致性算法

1、CAP 定理

对于一个分布式系统中,CAP 三者不可兼得,最多只能同时满足其中的两个。

  • 一致性 Consistency:所有的节点在同一时间的数据一致
  • 可用性 Availability:服务在正常响应时间内可用
  • 分区容错性 Partition-tolerance:分区故障仍能对外提供一致性或可用性服务。

一致性问题的是在于分区(多台服务器)。数据冗余可以提供系统的可用性和分区容错性,但是难以满足强一致性;若要解决一致性问题,达到强一致性,需要把所有请求全部通过单台服务器处理,很难达到可用性。

因此,对于分布式系统,需要在一致性、可用性和分区容错性间中取舍。从经验上看,可用性或一致性往往是被弱化的对象。

对于高可用的系统来说,往往保留强一致性。因此,计算机界通过共识算法来解决此类问题。

共识算法保证所有的参与者都有相同的认知,即强一致性。常见的共识算法有:

  • paxos 算法:代表 Zookeeper
  • Raft 算法:代表 Etcd

本文主要介绍 Raft 一致性算法。流程演示可参考:Raft 算法流程

1、Raft 基本概念

Raft 算法是主从模型(单 Leader 多 Follower)。所有的请求全部由 Leader 处理。Leader 处理请求时,先追加一条日志,然后把日志同步给 Follower。当写入成功的节点过半后持久化日志,通知 FoLLower 持久化,将结果返回给客户端。

Raft 节点有三种角色

  • Leader
  • Candidate
  • Follower

Raft 投票机制

  • 节点不能重复投票。Follower 节点记录自己投过的节点,在一个任期内不会重复投票
  • 一节点一票。Candidate 节点投给自己,Follower 节点投给向自己拉票的 Candidate

Raft 节点间使用的消息有两种

  • RequesetVote:请求其他节点给自己投票,由 Candidate 节点发出
  • AppendEntries:附加条目,条目数量 > 0,日志复制;条目数量 = 0,心跳信息,由 Leader 节点发出

任期 Term:逻辑时钟值,全局递增,描述一个 Leader 的任期

2、Raft 算法核心

Raft 算法核心是:

  • Leader 选举
  • 日志复制

2.1、Leader 选举

Leader 选举流程

  • 集群中的节点刚启动时,所有节点都是 Follower 节点。
  • 当 Leader 发送的心跳超时,Follower 节点选举超时自动变成 Candidate 节点,自荐成为选举候选人,并向其他节点发送 RequesetVote 消息
  • 若 Candidate 节点收到过半支持 (n+1)/2 后,变成 Leader 节点。新的 Leader 节点立即向其他节点发送心跳消息 AppendEntries,其他节点重置自己的选举超时时间,并保持 Follower 角色。

当集群节点数是偶数,可能会出现平票的情况,如图所示,两个 Candidate 节点分别得到 2 票,票数均未过半,无法选出 Leader 节点,该现象被称为分割选举 split vote。进入下一轮选举。

为了避免分割选举的现象出现,Raft 算法使用随机选举超时来降低 split vote 出现的概率。这样每个节点成为 Candidate 节点的时间点被错开了,提高了 Leader 节点选举成功的概率。

在选出 Leader 节点后,各个节点需要在最短时间内获取新的 Leader 节点信息,否则选举超时又会进入新一轮选举。因此心跳超时 << 选举超时。

节点的选举时间在收到心跳消息后会重置。如果不重置,节点会频繁发起选举。这样避免了节点频繁发起选举,系统收敛于稳定状态。只要 Leader 持续不断发送心跳信息,Follower 节点就不会成为 Candidate 角色并发起选举。

至此,选举结束,Leader 节点和 Follower 节点间开始日志同步。

任何导致心跳超时的事件,例如:集群启动、Leader 节点宕机、网络分区等,都会导致集群 Leader 选举。

Leader 选举控制

  • 心跳超时:Follower 节点在规定时间内没有收到 leader 的心跳消息。
  • 选举超时:随机值,Follower 等待变成 Candidate 的时间。定时器到期,Follower 节点自动成为 Candidate 节点,选举任期 + 1。
可以这样理解:
- Leader 节点是君主,Follower 节点是有野心的臣子,蠢蠢欲动,随时密谋造反。只要Leader 定期发号施令(心跳消息),Follower 收到心跳消息后,忌惮君主实力,不敢造反(重置选举超时)。
- 倘若一段时间后 Follower 不再收到君主的消息(心跳超时),Follower 准备妥当后(选举超时)成为 Candidate。自立为王,并胁迫其他 Follower 支持自己(RequesetVote 消息)。一旦获得半数以上的 Follower 支持,新王加冕。
- 新的 Leader 立刻发送心跳消息,迫使其他 Candidate 放弃造反,继续保持 Follower 身份。

2.2、日志复制

Raft 算法中,所有来自客户端的数据变更请求都会被当作一个日志条目追加到节点日志中。

日志条目有以下两种状态:

  • 已追加,但是尚未提交(没有持久化)
  • 已提交(持久化)

Raft 算法中的节点维护已提交日志条目索引 commitIndex,小于等于该值的日志条目被认为是已提交,否则就是尚未持久化的数据。

Raft 日志复制流程

  • 日志追加
  • 日志提交

客户端向 Leader 发送数据变更请求,Leader 节点向自己的本地日志中追加一条日志,接下来通过 AppendEntries 消息向其他节点同步数据。当超过半数节点(包括 Leader 自己)追加新日志成功后,Leader 节点持久化本地日志并提交日志,然后再次通过 AppendEntries 消息通知其他节点持久化日志。

一般情况,日志复制需要来回发送两次 AppendEntries 消息(追加日志和提交日志)。需要发送两次的主要原因是需要确保过半追加成功后,系统才能正常提交日志。假设不确认过半追加,当碰到脑裂或者网络分区时,会出现数据严重不一致的问题。

例如:如图所示,Raft 集群中,原 Leader 是 B 节点,其他都是 Follower,任期是 1。在某一时刻出现网络分区,节点 A、B 处在同一分区,A 仍可以接受 B 的心跳信息,保持 Follower。节点 C、D、E 无法收到 B 的心跳消息,选举超时后,选举 C 作为新的 Leader 节点,任期 + 1。

当客户端连接节点 B 和 C 分别写入,对于分区 A、B,追加日志后,没有收到半数以上节点的确认(2 个节点),无法提交日志;对于分区 C、D、E,追加日志后,收到半数以上节点的确认(3 个节点),提交日志成功。此时,Leader B 和 Leader C 日志冲突。

当网络分区恢复后,Leader B 节点发现 Leader C 节点的任期 Term 的值更高, 降级为 Follower。则节点 A 和 B 丢弃自己的日志,同步 Leader C 的日志消息。此时,日志保持一致。

3、总结

Raft 的读写

所有来自客户端的读写请求,全部由 Leader 节点处理。

Raft 节点的三种状态

  • Follower:随机选举超时,自动成为 Candidate
  • Candidate:主动给自己投票,向其他节点广播拉票,当自身选票超过半数以上成为 Leader
  • Leader:定时向其他节点发送心跳消息,并同步变化信息;若 Leader 发现有比自身更高的任期,则降级为 Follower,并接受新的 Leader 的数据变更同步

Raft 节点的状态变化

  • Follower -> Candidate:选举超时,自动成为 Candidate
  • Candidate -> Candidate:本轮选举超时,开启新一轮选举
  • Candidate -> Leader:获得半数以上节点的支持
  • Leader -> Follower:发现更高的任期
  • Candidate -> Follower:收到 Leader 的心跳消息

Follower 处理其他节点发送来的消息

  • candidate:向第一次接收到的拉票所属 candidate 发送投票,并将自己的任期设置为该 candidate 的任期。同时会重置自身选举超时和心跳超时
  • Leader:重置自身选举超时和心跳超时

平票后,下一轮选举

  • 选举任期 Term + 1
  • 重新随机一个选举超时
  • 重置上轮的选票

日志复制流程

  • 日志追加:收到数据变更请求,Leader 将追加日志到本地,向其他节点同步数据,待半数以上节点追加成功后,开始日志持久化。
  • 日志提交:Leader 将本地日志持久化,并通知其他节点日志持久化。

Raft 修复脑裂后,如何恢复一致性

  • 发生脑裂:无法接收到心跳消息的分区重新选举新的 Leader 节点,分区内所有节点任期 + 1
  • 修复脑裂:若 Leader 节点发现集群中有比自己任期还高的 Leader 节点, 则降级为 Follower,接收 Leader 的数据同步
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
30天前
|
算法
raft算法的自我理解
本文介绍了Raft算法的基本概念和工作原理,包括它如何通过日志复制和领导选举来实现分布式系统中不同机器的强一致性。
23 2
|
4月前
|
算法
Bully、Raft、Zab选举算法的差异比较
Bully算法、Raft算法、Zab的差与异。他们如何脱胎于Paxos而成?
|
3月前
|
存储 算法 NoSQL
(七)漫谈分布式之一致性算法下篇:一文从根上儿理解大名鼎鼎的Raft共识算法!
Raft通过一致性检查,能在一定程度上保证集群的一致性,但无法保证所有情况下的一致性,毕竟分布式系统各种故障层出不穷,如何在有可能发生各类故障的分布式系统保证集群一致性,这才是Raft等一致性算法要真正解决的问题。
107 11
|
3月前
|
存储 算法 索引
(六)漫谈分布式之一致性算法上篇:用二十六张图一探Raft共识算法奥妙之处!
现如今,大多数分布式存储系统都投向了Raft算法的怀抱,而本文就来聊聊大名鼎鼎的Raft算法/协议!
108 8
|
3月前
|
存储 算法 Java
(五)漫谈分布式之一致性算法篇:谁说Paxos晦涩难懂?你瞧这不一学就会!
没在时代发展的洪流中泯然于众的道理很简单,是因为它们并不仅是空中楼阁般的高大上理论,而是有着完整落地的思想,它们已然成为构建分布式系统不可或缺的底层基石,而本文则来好好聊聊分布式与一致性思想的落地者:Paxos与Raft协议(算法)。
|
4月前
|
缓存 负载均衡 算法
(四)网络编程之请求分发篇:负载均衡静态调度算法、平滑轮询加权、一致性哈希、最小活跃数算法实践!
先如今所有的技术栈中,只要一谈关于高可用、高并发处理相关的实现,必然会牵扯到集群这个话题,也就是部署多台服务器共同对外提供服务,从而做到提升系统吞吐量,优化系统的整体性能以及稳定性等目的。
|
4月前
|
算法
共识协议的技术变迁问题之Raft的选举算法进行如何解决
共识协议的技术变迁问题之Raft的选举算法进行如何解决
|
6月前
|
缓存 负载均衡 算法
C++如何实现一致性算法
一致性哈希是一种用于分布式系统的负载均衡算法,旨在减少服务器增减导致的数据迁移。当有N台服务器时,通过哈希环将请求均匀分布到每台服务器,每台处理N/1的请求。若使用缓存如Redis,可进一步处理高并发场景。算法将哈希值空间视为环形,服务器和请求哈希后定位到环上,按顺时针方向找到第一台服务器作为负载目标。提供的C++代码实现了MD5哈希函数,以及一致性哈希算法的物理节点、虚拟节点和算法本身,以实现节点的添加、删除和请求映射。
44 1
C++如何实现一致性算法
|
12天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
|
9天前
|
人工智能 算法 数据安全/隐私保护
基于遗传优化的SVD水印嵌入提取算法matlab仿真
该算法基于遗传优化的SVD水印嵌入与提取技术,通过遗传算法优化水印嵌入参数,提高水印的鲁棒性和隐蔽性。在MATLAB2022a环境下测试,展示了优化前后的性能对比及不同干扰下的水印提取效果。核心程序实现了SVD分解、遗传算法流程及其参数优化,有效提升了水印技术的应用价值。