raft论文学习.md

2019-10-12  本文已影响0人  斜不靠谱

raft

1. 特点

2. 一致性算法的典型属性

3 raft概况

同步状态机架构图


image.png

3.1 State

3.1.1 所有节点都会持久化的状态信息

(响应rpc前会先持久化)

3.1.2 所有节点都会保存的非持久化信息

3.1.3 leaders才会保存的非持久化信息

(选举后会重新初始化)

3.2 AppendEntries RPC

(leader同步log entry,以及心跳相关操作)

3.2.1 Arguments

3.2.2 Results

3.2.3 Receiver implementation

3.3 RequestVote RPC

(candidates 获取 选举信息)

3.3.1 arguments

3.3.2 results

3.3.3 Receiver implementation(返回说明)

3.4 Rules for Servers

3.4.1 All Servers

3.4.2 Followers

3.4.3 Candidates

3.4.4 Leaders

3.5 raft会保证整个生命周期如下的规则

3.6 server节点角色

image.png

4 raft一致性算法详细介绍

raft算法分为三个独立的部分:

以下列出论文中的条目,方便有个全局印象

4.1 Raft basics

一般一个raft集群包含5个节点(可以允许两个节点异常),任何时间点下server只会是 leader,follower或者candidate中的一个角色.正常运行情况下,只会有一个leader,其他节点都为follower. follower只会被动接收leader和candidate的request而不会主动发送请求.leader处理所有客户端的请求(如果client连接flolower,会转接给leader). candidate用于选举leader时的中间状态.
raft会把时间划分到任意长度的term,term是连续递增编号的,最开始的term会先发起选举,如果有candidate赢得选举,则会成为leader,如果选举冲突,则会在下一个term重新选举.raft确保在同一个term下,最多有一个leader
term就是raft里的逻辑时钟,每个server都会保存一个当前term值,term会随着时间递增.current term信息会在集群内不断交换,如果一个server的current term比其他server小,会更新到较大的那个值,如果一个candidate或leader发现自己的term是过期的,则会降级为follower,如果server收到term老旧的request,server会拒绝响应.
raft使用rpc进行通信,基本的raft算法只需要两种rpc服务,RequestVote rpc是在选举期间由候选人发起,Append-Entries RPCs 则是由leader发起的用于replicate log entries 和 heartbeat. raft还有第三种rpc服务(InstallSnapshot RPC),用于在服务器之间传输快照

4.2 Leader election

raft通过heartbeat机制触发选举.server启动时,会作为followers角色,并且只要能够收到来自leader或candidate有效的rpc请求,server会一直保持followers角色,如果超过election timeout没有收到heartbeat, 则会认为当前没有可用的leader节点,并会发起选举.
要发起选举,follower会先增加自己的term并且转变为candidate角色,选举自己为leader,并且并发的向其他节点发起 RequestVote RPCs ,结果会有三种:
1 自己赢得选举成为leader
2 其他节点赢得选举成为leadder
3 没有节点赢得选举
下面分别探讨三种情况

  1. 如果大多数server选举的candidate会成为leader,每个server在同一个term下最多给一个server投票(谁先发起RequestVote,选举谁),candidate成为leader后,发送heartbeat给各个节点,防止新的选举发生
  2. candidate在等待选举结果时,如果收到leader发送的AppendEntries RPC,并且leader’s term (included in its RPC) 不低于 candidate’s current term,则认为leader是合法的,自己降级为follower,如果leader的term低于自己的current term,则会忽略,继续保持 candidate 状态
  3. 如果多个candidate发起选举,并且都没有能赢得大多数的投票,则会等待选举超时后,增加term,发起新一轮的选举.

raft使用随机的 election timeouts 来避免选举冲突,一般为150–300ms范围内的随机值.相同的机制用于处理分裂投票。每个候选人在选举开始时重新启动随机化的选举超时,并在开始下一次选举前等待超时时间的流逝;这减少了在新选举中再次出现分裂投票的可能性。

4.3 Log replication

leader被选举出来后,就可以响应客户端的请求.一个client的请求包含一个replicated state machines要执行的命令.leader会将命令添加到log , 然后并发给每个节点的发起 AppendEntries RPCs,entry被safely复制后,leader应用entry到state machine中,并返回成功给client.如果followers crash或响应慢或者网络有问题,leader会不定期重新发送 Append-Entries RPCs (即使leader 已经responded client),直到followers最终存储所有的log.

log的组织形式如下图:


image.png

每个log entry包含一个state machine命令以及leader接收entry的term编号.log entries中的term可以用来探测不一致.每个log entry还有一个index编号,确认在log里的位置.

leader决定何时应用log entry到state machine,成为一个提交了的log entry. raft确保已经提交的erntry最终会被所有节点应用到可用的state machines.一旦leader将log etnry同步到大多数节点,该条log就被提交.
raft会维护如下属性:

4.4 Safety

本节通过添加对哪些服务器可以被选为leader的限制来完成Raft算法。这个限制确保任何给定期限的leader获得在以前期限中提交的所有条目。最后,我们给出了Leader完备性的一个证明图,并展示了它是如何导致复制状态机的正确行为的。

4.4.1 Election restriction

在任何基于领导的协商一致算法中,领导最终必须存储所有提交的日志条目。在一些协商一致的算法中,比如Viewstamped Replication[22],可以选出一个leader,即使它最初不包含所有提交的条目。这些算法包含额外的机制来识别缺失的条目,并在选举过程中或选举后不久将其发送给新领导人。不幸的是,这导致相当多的额外机械和复杂性。Raft使用了一种更简单的方法,它保证所有来自previousterm的提交条目从每个新领导者当选的那一刻起就存在,而不需要将这些条目传递给领导者。这意味着日志条目只在一个方向上流动,即从leader到follower。
raft通过在选举中添加限制来确保只有包含所有已经提交的log的节点才能选举成功.因为要多数节点选举才能成为leader,至少在其中一个节点包含所有提交的entry,进而,如果candidate比大多数节点的log都up-to-date则可以确保该candidate包含所有已经提交的信息(如果voter比candidate的log更up-to-date则不会选举它)
raft通过比较最后一条entry的index和term来判断哪个更加up-to-date,如果两个log term不相同,则term较大的更up-to-date,如果term相同,则log越长的越up-to-date

4.4.2 Committing entries from previous terms

旧leader crash之后,新的leader会尝试在之前的基础上完成entry的复制,但是即使大部分节点同步了一个entry,也不能确定确认entry已经提交,下图给出了一种大多数节点已经同步log的情况下,依然被新leader覆盖掉的情况(term是基于时间生成的)


image.png

为了避免上面的情况,raft不会根据已经同步的replicas个数来确认是提交.只有leader当前term的提交才会根据是否有大多数节点同步,只要当前term的entry被提交,则所有之前的entry也可以通过 Log Matching Property来间接保证提交.

4.5 Safety argument

以下通过反证法,证明raft能够保证数据完整性.
假设leader(leader_T)提交 term T log,但是term T log没有在新的term的leader(leader_U U>T)中保存,则可以作出如下推测:

最后,raft要求server按照 log index顺序应用 log entry,与 State Machine Safety Property 相结合,共同确保所有节点的state machines会按照相同的顺序应用log

4.6 Follower and candidate crashes

如果一个follower或者candidate crash,那么后续的RequestVote和AppendEntries RPCs 就会失败,raft会不定期的重试,如果crash的节点重新启动,rpc会成功.如果一个server在完成rpc请求,但是在返回成功前crash,则会在重启后收到一个相同的rpc请求,因为raft的rpc请求是幂等的,所以不用做特殊处理.例如,如果follower收到的AppendEntries请求里的log与当前log包含一样的内容,节点会忽略这些entries

4.7 Timing and availability

raft集群必须要满足如下时间关系,否则无法正常选主,对外提供服务:
broadcastTime ≪ electionTimeout ≪ MTBF
其中:

5 Cluster membership changes

配置变更时,如果只是简单的逐个变更,则可能会有同一个term下,两个主的危险,如下图所示:


image.png

为了避免上面的问题,raft使用两阶段提交来变更配置,首先切换为变更配置状态( joint consensus),joint consensus 提交后,集群使用新的配置,joint consensus combines both the old and new configurations:

6 log compaction

raft的log会逐渐增长,需要做压缩清理,Snapshotting是一种最简便的方式,下图展示了snapshots的基本流程.


image.png

每个server独立的获取快照,覆盖已经提交的log,主要的工作就是state machine 将当前状态写入快照.raft快照中还会包含一部分的metadata,主要为最后一条log的index和term信息,主要是用于AppendEntries的一致性检查.此外,为了方便 membership changes, snapshot还会包含最新的configuration信息.一旦server完成了snapshot,就可以把之前的log entry和之前的snapshot都给清理掉.
虽然server会各自做snapshot,但是leader还是会偶尔发送snapshots到有延迟的节点(发生在follower延迟较高,leader把它所需要的next log entry已经清理的情况下,一般发生在新加入节点的情况).
leader会有InstallSnapshot RPC来发送snapshots给followers,如下图所示:


image.png

follower收到InstallSnapshot RPC后必须要决定怎么处理现存的log entry.一般是收到的InstallSnapshot RPC中日志比server的新,则server会将之前的log清理掉,如果是当前的log已经比Snapshot 更新,则将冲突的部分覆盖清理掉,更新的部分则保留.
还有另外两个影响快照的问题。首先,服务器必须决定何时进行快照。如果服务器快照太频繁,就会浪费磁盘带宽和能量;如果快照太不频繁,就有耗尽存储容量的风险,还会增加重新启动时重播日志所需的时间。一个简单的策略是在日志达到固定大小(以字节为单位)时捕获快照。如果将此大小设置为比快照的预期大小大得多,那么用于快照的磁盘带宽开销将很小。
第二个问题是,编写快照可能会花费大量时间,我们不希望这会延迟正常的操作。解决方案是使用即写即拷技术,这样就可以接受新的更新,而不会影响正在写入的快照。例如,使用 functional data structures构建的state machines 自然支持这一点。或者,操作系统的写时复制支持(例如,Linux上的fork)可以用来创建整个状态机的内存快照(我们的实现使用这种方法)。

7 Client interaction

如果client发送请求到raft集群后,raft已经提交,但是leader在返回response给client前crash,则client会任务没有提交成功,则会重新在新的leader上再此执行导致错误.因此client会给每个command一个唯一的编号,state machine在处理请求时也会保存每个client对应的编号,如果收到command的编号已经执行过,则会直接返回,防止再次执行.
在做读操作的时候因为没有写操作,client连接的leader时是无法确认这个leader是否已经被排除,已经选举出来新的leader,因此需要额外工作,确保数据是否为最新.

参考

https://raft.github.io/raft.pdf

上一篇下一篇

猜你喜欢

热点阅读