解读Raft(一 算法基础)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 最近工作中讨论到了Raft协议相关的一些问题,正好之前读过多次Raft协议的那paper,所以趁着讨论做一次总结整理。   我会将Raft协议拆成四个部分去总结:   算法基础 选举和日志复制 安全性 节点变更   这是第一篇:《解读Raft(一 算法基础)》   什么是RAFT 分布式系统除了提升整个体统的性能外还有一个重要特征就是提高系统的可靠性。

最近工作中讨论到了Raft协议相关的一些问题,正好之前读过多次Raft协议的那paper,所以趁着讨论做一次总结整理。

 

我会将Raft协议拆成四个部分去总结:

 

  1. 算法基础

  2. 选举和日志复制

  3. 安全性

  4. 节点变更

 

这是第一篇:《解读Raft(一 算法基础)》

 

什么是RAFT

分布式系统除了提升整个体统的性能外还有一个重要特征就是提高系统的可靠性。

提供可靠性可以理解为系统中一台或多台的机器故障不会使系统不可用(或者丢失数据)。

保证系统可靠性的关键就是多副本(即数据需要有备份),一旦有多副本,那么久面临多副本之间的一致性问题。

一致性算法正是用于解决分布式环境下多副本之间数据一致性的问题的。

业界最著名的一致性算法就是大名鼎鼎的Paxos(Chubby的作者曾说过:世上只有一种一致性算法,就是Paxos)。但Paxos是出了名的难懂,而Raft正是为了探索一种更易于理解的一致性算法而产生的。

Raft is a consensus algorithm for managing a replicated log. 

Raft是一种管理复制日志的一致性算法。

它的首要设计目的就是易于理解,所以在选主的冲突处理等方式上它都选择了非常简单明了的解决方案。

Raft将一致性拆分为几个关键元素:

  • Leader选举

  • 日志复制

  • 安全性

Raft算法

所有一致性算法都会涉及到状态机,而状态机保证系统从一个一致的状态开始,以相同的顺序执行一些列指令最终会达到另一个一致的状态。

以上是状态机的示意图。所有的节点以相同的顺序处理日志,那么最终x、y、z的值在多个节点中都是一致的。

算法基础

角色

Raft通过选举Leader并由Leader节点负责管理日志复制来实现多副本的一致性。

在Raft中,节点有三种角色:

  • Leader:负责接收客户端的请求,将日志复制到其他节点并告知其他节点何时应用这些日志是安全的

  • Candidate:用于选举Leader的一种角色

  • Follower:负责响应来自Leader或者Candidate的请求

角色转换如下图所示:

  • 所有节点初始状态都是Follower角色

  • 超时时间内没有收到Leader的请求则转换为Candidate进行选举

  • Candidate收到大多数节点的选票则转换为Leader;发现Leader或者收到更高任期的请求则转换为Follower

  • Leader在收到更高任期的请求后转换为Follower

任期

Raft把时间切割为任意长度的任期,每个任期都有一个任期号,采用连续的整数。

 

每个任期都由一次选举开始,若选举失败则这个任期内没有Leader;如果选举出了Leader则这个任期内有Leader负责集群状态管理。

算法

状态

状态 所有节点上持久化的状态(在响应RPC请求之前变更且持久化的状态)
currentTerm 服务器的任期,初始为0,递增
votedFor 在当前获得选票的候选人的 Id
log[] 日志条目集;每一个条目包含一个用户状态机执行的指令,和收到时的任期号
状态 所有节点上非持久化的状态
commitIndex 最大的已经被commit的日志的index
lastApplied 最大的已经被应用到状态机的index
状态 Leader节点上非持久化的状态(选举后重新初始化)
nextIndex[] 每个节点下一次应该接收的日志的index(初始化为Leader节点最后一个日志的Index + 1)
matchIndex[] 每个节点已经复制的日志的最大的索引(初始化为0,之后递增)

AppendEntries RPC

用于Leader节点复制日志给其他节点,也作为心跳。

参数 解释
term Leader节点的任期
leaderId Leader节点的ID
prevLogIndex 此次追加请求的上一个日志的索引
prevLogTerm 此次追加请求的上一个日志的任期
entries[] 追加的日志(空则为心跳请求)
leaderCommit Leader上已经Commit的Index

prevLogIndex和prevLogTerm表示上一次发送的日志的索引和任期,用于保证收到的日志是连续的。

返回值 解释
term 当前任期号,用于Leader节点更新自己的任期(应该说是如果这个返回值比Leader自身的任期大,那么Leader需要更新自己的任期)
success 如何Follower节点匹配prevLogIndex和prevLogTerm,返回true

接收者实现逻辑

  1. 返回false,如果收到的任期比当前任期小

  2. 返回false,如果不包含之前的日志条目(没有匹配prevLogIndex和prevLogTerm)

  3. 如果存在index相同但是term不相同的日志,删除从该位置开始所有的日志

  4. 追加所有不存在的日志

  5. 如果leaderCommit>commitIndex,将commitIndex设置为commitIndex = min(leaderCommit, index of last new entry)

RequestVote RPC

用于Candidate获取选票。

参数 解释
term Candidate的任期
candidateId Candidate的ID
lastLogIndex Candidate最后一条日志的索引
lastLogTerm Candidate最后一条日志的任期
参数 解释
term 当前任期,用于Candidate更新自己的任期
voteGranted true表示给Candidate投票

接收者的实现逻辑

  1. 返回false,如果收到的任期比当前任期小

  2. 如果本地状态中votedFor为null或者candidateId,且candidate的日志等于或多余(按照index判断)接收者的日志,则接收者投票给candidate,即返回true

节点的执行规则

所有节点

  • 如果commitIndex > lastApplied,应用log[lastApplied]到状态机,增加lastApplied

  • 如果RPC请求或者响应包含的任期T > currentTerm,将currentTerm设置为T并转换为Follower

Followers

  • 响应来自Leader和Candidate的RPC请求

  • 如果在选举超时周期内没有收到AppendEntries的请求或者给Candidate投票,转换为Candidate角色

Candidates

  • 转换为candidate角色,开始选举:

    • 递增currentTerm

    • 给自己投票

    • 重置选举时间

    • 发送RequestVote给其他所有节点

  • 如果收到了大多数节点的选票,转换为Leader节点

  • 如果收到Leader节点的AppendEntries请求,转换为Follower节点

  • 如果选举超时,重新开始新一轮的选举

Leaders

  • 一旦选举完成:发送心跳给所有节点;在空闲的周期内不断发送心跳保持Leader身份

  • 如果收到客户端的请求,将日志追加到本地log,在日志被应用到状态机后响应给客户端

  • 如果对于一个跟随者,最后日志条目的索引值大于等于 nextIndex,那么:发送从 nextIndex 开始的所有日志条目:

    • 如果成功:更新相应跟随者的 nextIndex 和 matchIndex

    • 如果因为日志不一致而失败,减少 nextIndex 重试

    • 如果存在一个满足N > commitIndex的 N,并且大多数的matchIndex[i] ≥ N成立,并且log[N].term == currentTerm成立,那么令commitIndex等于这个N

如果本文对您有帮助,点一下右下角的“推荐”
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
6月前
|
消息中间件 算法 分布式数据库
Raft算法:分布式一致性领域的璀璨明珠
【4月更文挑战第21天】Raft算法是分布式一致性领域的明星,通过领导者选举、日志复制和安全性解决一致性问题。它将复杂问题简化,角色包括领导者、跟随者和候选者。领导者负责日志复制,确保多数节点同步。实现细节涉及超时机制、日志压缩和网络分区处理。广泛应用于分布式数据库、存储系统和消息队列,如Etcd、TiKV。其简洁高效的特点使其在分布式系统中备受青睐。
|
1月前
|
算法
raft算法的自我理解
本文介绍了Raft算法的基本概念和工作原理,包括它如何通过日志复制和领导选举来实现分布式系统中不同机器的强一致性。
28 2
|
4月前
|
算法
Bully、Raft、Zab选举算法的差异比较
Bully算法、Raft算法、Zab的差与异。他们如何脱胎于Paxos而成?
|
3月前
|
存储 算法 NoSQL
(七)漫谈分布式之一致性算法下篇:一文从根上儿理解大名鼎鼎的Raft共识算法!
Raft通过一致性检查,能在一定程度上保证集群的一致性,但无法保证所有情况下的一致性,毕竟分布式系统各种故障层出不穷,如何在有可能发生各类故障的分布式系统保证集群一致性,这才是Raft等一致性算法要真正解决的问题。
112 11
|
3月前
|
存储 算法 索引
(六)漫谈分布式之一致性算法上篇:用二十六张图一探Raft共识算法奥妙之处!
现如今,大多数分布式存储系统都投向了Raft算法的怀抱,而本文就来聊聊大名鼎鼎的Raft算法/协议!
113 8
|
4月前
|
算法
共识协议的技术变迁问题之Raft的选举算法进行如何解决
共识协议的技术变迁问题之Raft的选举算法进行如何解决
101 7
|
6月前
|
算法 程序员 分布式数据库
分布式一致性必备:一文读懂Raft算法
Raft算法是一种用于分布式系统中复制日志一致性管理的算法。它通过选举领导者来协调日志复制,确保所有节点数据一致。算法包括心跳机制、选举过程、日志复制和一致性保证。当领导者失效时,节点会重新选举,保证高可用性。Raft易于理解和实现,提供强一致性,常用于分布式数据库和协调服务。作者小米分享了相关知识,鼓励对分布式系统感兴趣的读者进一步探索。
1310 0
|
6月前
|
算法 Go 分布式数据库
构建高可用的分布式数据库集群:使用Go语言与Raft共识算法
随着数据量的爆炸式增长,单一数据库服务器已难以满足高可用性和可扩展性的需求。在本文中,我们将探讨如何使用Go语言结合Raft共识算法来构建一个高可用的分布式数据库集群。我们不仅会介绍Raft算法的基本原理,还会详细阐述如何利用Go语言的并发特性和网络编程能力来实现这一目标。此外,我们还将分析构建过程中可能遇到的挑战和解决方案,为读者提供一个完整的实践指南。
|
6月前
|
存储 算法 安全
5. raft 一致性算法
5. raft 一致性算法
|
6月前
|
负载均衡 算法 应用服务中间件
Docker Swarm总结+service创建和部署、overlay网络以及Raft算法(2/5)
Docker Swarm总结+service创建和部署、overlay网络以及Raft算法(2/5)
812 0