Raft 协议实战系列(一)—— 基本概念

3,236 阅读6分钟

注:本文原创,转载请标明出处。

欢迎转发、关注微信公众号:Q的博客。 不定期发送干货,实践经验、系统总结、源码解读、技术原理。


本文目的

笔者期望通过该系列文章帮助读者深入理解Raft协议并能付诸于工程实践中,同时解读不易理解或容易误解的关键点。

本文为《Raft实战》系列开篇,该系列会从原理、源码、实践三个部分为大家讲解Raft算法:

  • 原理部分我们会结合Raft论文讲解 Raft 算法思路,整体分篇会遵循 Raft 的模块化思想,分别讲解 Leader election、Log replication、Safety、Cluster membership change、Log compaction 等。

  • 源码部分我们会通过分析 hashicorp/raft 来学习一个工业界的 Raft 实现,hashicorp/raft 是 Consul 的底层依赖。

  • 实践部分我们会基于 hashicorp/raft 来实现一个简单的分布式 kv 存储,以此作为系列的收尾。


Raft是什么?

Raft is a consensus algorithm for managing a replicated log. It produces a result equivalent to (multi-)Paxos, and it is as efficient as Paxos, but its structure is different from Paxos; this makes Raft more understandable than Paxos and also provides a better foundation for building practical systems.

--《In Search of an Understandable Consensus Algorithm》

在分布式系统中,为了消除单点提高系统可用性,通常会使用副本来进行容错,但这会带来另一个问题,即如何保证多个副本之间的一致性?

所谓的一致性并不是指集群中所有节点在任一时刻的状态必须完全一致,而是指一个目标,即让一个分布式系统看起来只有一个数据副本,并且读写操作都是原子的,这样应用层就可以忽略系统底层多个数据副本间的同步问题。也就是说,我们可以将一个强一致性(线性一致性)分布式系统当成一个整体,一旦某个客户端成功的执行了写操作,那么所有客户端都一定能读出刚刚写入的值。即使发生网络分区故障,或者少部分节点发生异常,整个集群依然能够像单机一样提供服务。

共识算法(Consensus Algorithm)就是用来做这个事情的,它保证即使在小部分(≤ (N-1)/2)节点故障的情况下,系统仍然能正常对外提供服务。共识算法通常基于状态复制机(Replicated State Machine)模型,也就是所有节点从同一个 state 出发,经过同样的操作 log,最终达到一致的 state。

Replicated State Machine

共识算法是构建强一致性分布式系统的基石,Paxos 是共识算法的代表,而 Raft 则是其作者在博士期间研究 Paxos 时提出的一个变种,主要优点是容易理解、易于实现,甚至关键的部分都在论文中给出了伪代码实现。

Raft基本概念

Raft一致性相关子问题

Raft 使用 Quorum 机制来实现共识和容错,我们将对 Raft 集群的操作称为提案,每当发起一个提案,必须得到大多数(> N/2)节点的同意才能提交。

Raft 核心算法将一致性问题拆分为三个子问题,逐个解决,大大提升了算法的易用性:

  • Leader election

    • 集群中必须存在一个 leader 节点。
  • Log replication

    • Leader 节点负责接收客户端请求,并将请求操作序列化成日志同步。
  • Safety

    • 包括 leader 选举限制、日志提交限制等一系列措施,来确保 state machine safety。

除核心算法外还有集群成员变更、日志压缩等。

集群中节点角色概念

Raft 集群中每个节点都处于以下三种角色之一:

  • Leader

    • 所有请求的处理者,接收客户端发起的操作请求,写入本地日志后同步至集群其它节点。
  • Follower

    • 请求的被动更新者,从 leader 接收更新请求,写入本地文件。如果客户端的操作请求发送给了 follower,会首先由 follower 重定向给 leader。
  • Candidate

    • 如果 follower 在一定时间内没有收到 leader 的心跳,则判断 leader 可能已经故障,此时启动 leader election 过程,本节点切换为 candidate 直到选主结束。

选举相关概念

每开始一次新的选举,称为一个 term,每个 term 都有一个严格递增的整数与之关联。

节点的状态切换如图所示:

节点状态图

具体说明如下:

  • Starts up

    • 节点刚启动时自动进入 follower 状态。
  • Times out, starts election

    • 进去 follower 状态后开启一个选举定时器,到期时切换为 candidate 并发起选举,leader 节点的心跳会部分重置这个定时器。
  • Times out, new election

    • 进入 candidate 状态后开启一个超时定时器,如果到期时还未选出新的 leader,就保持 candidate 状态并重新开始下一次选举。
  • Receives votes from majority of servers

    • Candidate 状态节点收到半数以上选票,切换状态成为新的 leader。
  • Discovers current leader or new term

    • Candidate 状态节点收到 leader 或更高 term 号(本文后续有介绍)的消息,表示已经有 leader 了,切回 follower。
  • Discovers server with higher term

    • Leader 节点收到更高 term 号的消息,表示已经存在新 leader 了,切回 follower。这种切换一般发生在网络分区时,比如旧 leader 宕机后恢复。

Term相关概念

每当 candidate 触发 leader election 时都会增加 term,如果一个 candidate 赢得选举,他将在本 term 中担任 leader 的角色,但并不是每个 term 都一定对应一个 leader,比如上述的 “times out, new election” 情况(对应下图中的t3),可能在选举超时时都没有产生一个新的 leader,此时将递增 term 号并开始一次新的选举。

Term 示意图

Term 更像是一个逻辑时钟(logic clock)的作用,有了它,可以发现哪些节点的状态已经过期。每一个节点都保存一个 current term,在通信时带上这个term号。

节点间通过 RPC 来通信,主要有两类 RPC 请求:

RequestVote RPCs: 用于 candidate 拉票选举

AppendEntries RPCs: 用于 leader 向其它节点复制日志以及同步心跳

Raft 的基本概念就是这些,下一篇我们将详细介绍 Leader election


欢迎转发、关注微信公众号:Q的博客,不定期发送干货,实践经验、系统总结、源码解读、技术原理。