Raft分布式一致性协议

1,149 阅读8分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情 >>

1. 分布式系统

  • 背景:随着数据规模越来越大,对服务的可用性要求越来越高,快速迭代的业务要求系统足够易用
  • 维度:高性能;正确;可靠
  • 一致性的定义:对于多台机器,要像操作一台机器一样,读到正确的最近写入的值。一致性是一种模型月约定一个分布式系统如何向外界应用提供服务

2. 实际设计和实现

如何设计kv既高可用又有一致性——从HDFS开始

  • 接口Get,BatchPut
  • 第一次实现RPC,DB Engine

单线程,使得所有的操作顺序进行

2.1 从复制开始

  • 一台机器会存在宕机的可能,使用备份

    • 主副本定期拷贝全量数据到从副本
    • 主副本拷贝操作到从副本
  • how

    • 主副本把所有的操作打包成log(log会持久化到磁盘上)
    • 应用包装成状态即,只接受Log作为Input
    • 主副本确认Log已经成功写入到副本机器上,当状态机apply后,返回客户端
  • 当意外发生,比如主副本失效

    • 可用性:人立即手工切换,能够保证较高的可用性
    • 如何保证真的失效?可能会出现脑裂问题
    • 容错性:增加到三个节点之后,会有长尾现象的发生,要允许少数节点失效,仍然可以工作
  • 脑裂问题:一个分布式系统中的机器不一致,对于两个不同客户端,存在两个不同状态,提供不同的结果。

    • 脑裂现象会导致两个节点都认为自己是这个集群的主节点,开始争抢彼此的共享资源和应用服务,这样就会发生严重后果

2.2 读操作

  • 直接读状态即,要求写操作进入状态机后再返回client
  • 写操作复制完成后直接返回,读操作Block等待所有的pending log进入状态机

2.3 一致性协议

KV中常见的一致性模型

  • 最终一致性:读取可能暂时读不到但是总会读到
  • 线性一致性:最严格,线性执行

2.4 共识算法

简而言之一个值一旦确认,所有人都认同

达成共识是个不可能的任务,因为

  • 错误总是会发生
  • 错误的类型有很多,比如网络断开,分区,缓慢,重传,乱序,cpu停滞
  • 容错

共识算法不等于一致性,应用层面不同的一致性都可以用共识协议来实现。简单的复制协议也可以提供线性一致性。

弱一致性能够使用简单的复制算法实现,共识协议提到的一致性是线性一致性

3. Raft一致性算法

Paxos:基本上是一致性协议的同义词。由于Paxos算法难以理解,工程上实现需要做一些修改。

Raft:2014年发表,易于理解。使用了RSM、Log、RPC的概念;直接使用RPC对算法进行描述;Strong Leader-based;使用了随机的方法减少约束;正确性也可以保证。TiDB和ETCD都使用了Raft算法

3.1 复制状态机(RSM)

replicated state machine: raft中所有的共识都使用Log作为载体

Commit Index:一旦Raft更新Commited Index,意味着这个Index前的所有Log都可以提交给状态机了。不持久化,状态机重启后从第一条Log开始。

3.2 角色

Raft算法中除了领导者(Leader),还支持其它两种成员身份(服务器状态)分别是跟随者(Follower)、候选人(Candidate)。在任何时候,每一个服务器节点都处于这3个状态中的一个。

image.png

1)跟随者(Follower):相当于普通群众,默默地接收和处理来自领导者的消息,当领导者心跳超时的时候,它就会主动站出来,推荐自己当候选人。

2)候选人(Candidate):向其他节点发送请求投票(RequestVote)RPC消息,通知其他节点来投票,如果赢得了大多数选票,就晋升为领导者。

3)领导者(Leader):相当于决策者,平常的主要工作内容就是3部分,处理写请求、管理日志复制和不断地发送心跳信息,通知其它结点“我是领导者,还活着,不要发起新的选举”。

3.3 整体流程

image.png

  • 假设在集群中,有A、B、C三个节点。初始状态下,所有的服务器都是跟随者(Follower)的状态,而没有领导者状态(Leader
  • 集群中每个节点都有一个选举超时时间(election timeout),每个节点的选举超时时间都是150ms~300ms的一个随机数,每当节点的选举超时时间到了就会触发它成为候选者。假设A节点的等待超时时间最小(150ms),它会最先因为没有等到领导者的心跳信息,发生超时。此时A节点的状态会由Follower转换成为Candidate状态。
  • A转换了自己的状态为Candidate,它会立即开始如下动作进行选举:1)增加了自己的term,2)先给自己投上一票,3)重置选举超时时间,4)然后向其他节点发送请求投票RPC消息,请它们选举自己为领导者。如果候选人在选举超时时间内赢得了大多数选票,它将成为本届任期内新的领导者。

3.4 Term任期

image.png Raft算法把时间分为任意不同长度的任期(term),每一个任期的开始都是领导人选举。term是一个全局的、连续递增的整数,每进行一次选举,term就会加一。

  • 如果处于Candidate状态状态的节点赢得了选举,它会当领导者直到任期结束。在成功选举之后,一个领导人会在任期内管理整个集群。
  • 如果选举失败,该任期就会因为没有领导人而结束。

为了保证Raft的安全性,在一个term中最多只会有一个leader

3.5 主节点失效

A当选领导者后,它将周期性地发送心跳信息,通知其它服务器“我是领导者”,阻止跟随者选举超时,发起新的选举。

跟随者们有不同的出发选举超时的时间,如果长时间没有收到心跳信息,跟随者发起一轮新的选举来选出一个新的领导人。

3.6 节点间通信

在Raft中,服务器节点间的沟通采用是远程过程调用(RPC),在领导者选举中,需要用到两类RPC。

1)请求投票RPC(RequestVote)RPC:是由Candidate发送给其他节点,请求其他节点为自己投票,如果一个Candidate获得了多数节点的投票,则该Candidate转变为Leader。

2)日志复制(Append Entries)RPC:是由Leader节点发送给其他节点,有两个作用,当其entries域为空时,该RPC作为Leader的心跳,当entries域不为空时,请求其他节点将entries域中的log添加到自己的log中。日志复制RPC只能由领导者发起。

  • 日志是对于数据一致的关键保证。副本数据是以日志的形式存在的,日志是由日志项组成。日志项是一种数据格式,它主要包含用户指定的数据,也就是指令(Command),还包含一些附加信息,比如索引值(Log index)、任期编号(Term)。索引值记录了在日志中的位置,任期编号表明该记录首次被创建时的任期号,可以用来检测在不同服务器上日志的不一致性。Raft日志的index和term唯一标示一条日志记录。

image.png

3.7 安全性验证

Raft使用TLA+进行了形式验证

4. Raft算法细节

4.1 集群成员变更

随着时间推移,会有机器故障需要替换,或者更改复制级别,修改节点数量。虽然通过关闭整个集群,升级配置文件,然后重启整个集群也可以解决这个问题,但是这回导致在更改配置的过程中,整个集群不可用,并且还存在操作失误的风险。

image.png 为了避免发生脑裂现象,使用一个两阶段(two-phase)协议。Raft通过共同一致(Joint Consensus)来完成两阶段协议,即:新、旧两种配置上都获得多数派选票。

image.png

4.2 水平扩展

多个副本只有单个副本可以提供服务是,服务无法进行水平扩展

4.3 日志压缩

当日志信息过多时,启用snapshot替换掉Log

image.png 快照一般包含以下内容:1)日志的元数据:最后一条被该快照apply的日志term及index;2)状态机:前边全部日志apply后最终得到的状态机。

4.4 选举合法leadership

  • 通过一轮心跳确定Leadership,同时保证选举时间不会有新的跟随者timeout

5. 更多优化

实际上系统需要us级别的共识,以及us级别的容错

5.1多节点提交

涉及到节点跨地域,节点间的RTT(Round Trip Time)很大

  • EPaxos使用了冲突图的方式来允许并行Commit
  • 不冲突的情况下减少RTT的提交时间

5.2 Raft优化移植到Paxos

5.3 共识算法作为系统

参考

PPT

Raft协议详解(三)日志复制 [EB/OL].

区块链系列----分布式一致性算法---Paxos 和 Raft

深度解析 Raft 分布式一致性协议

分布式存储引擎_Raft算法解读