浅析分布式一致性算法

  一致性算法的定义:一致性就是数据保持一致,在分布式系统中,可以理解为多个节点中数据的值是一致的。

一、为什么需要一致性

1、数据不能存在单个节点(主机)上,否则可能出现单点故障。

2、多个节点(主机)需要保证具有相同的数据。

3、一致性算法就是为了解决上面两个问题。

二、一致性分类

1、强一致性

  说明:保证系统改变提交以后立即改变集群的状态。

  模型:Paxos、Raft(muti-paxos)、ZAB(muti-paxos)

2、弱一致性

  说明:也叫最终一致性,系统不保证改变提交以后立即改变集群的状态,但是随着时间的推移最终状态是一致的。

  模型:DNS系统、Gossip协议

三、更加直观的 Raft 算法

  Raft 是用于一个管理日志一致性的协议,相比于 Paxos 协议 Raft 更易于理解和去实现它。为了提高理解性,Raft 将一致性算法分为了几个部分,包括领导选取(leader selection)、日志复制(log replication)、安全(safety),并且使用了更强的一致性来减少了必须需要考虑的状态。

1、解决什么问题

  分布式存储系统通常通过维护多个副本来提高系统的availability,带来的代价就是分布式存储系统的核心问题之一:维护多个副本的一致性。

  Raft 协议基于复制状态机(replicated state machine),即一组server从相同的初始状态起,按相同的顺序执行相同的命令,最终会达到一致的状态,一组server记录相同的操作日志,并以相同的顺序应用到状态机。

  Raft 有一个明确的场景,就是管理复制日志的一致性。如图,每台机器保存一份日志,日志来自于客户端的请求,包含一系列的命令,状态机会按顺序执行这些命令。一致性算法管理来自客户端状态命令的复制日志,保证状态机处理的日志中的命令的顺序都是一致的,因此会得到相同的执行结果。

2、Raft 状态

  相比 Paxos,Raft 算法理解起来直观的很。Raft算法将Server划分为3种状态,或者也可以称作角色。一个 Raft 集群包含若干个服务器节点;通常是 5 个,这允许整个系统容忍 2 个节点的失效,每个节点处于以下三种状态之一:

  • follower(跟随者) :所有节点都以 follower 的状态开始。如果没收到 leader 消息则会变成 candidate 状态  ——  被动响应请求RPC,从不主动发起请求RPC。
  • candidate(候选人):会向其他节点“拉选票”,如果得到大部分的票则成为leader。这个过程就叫做Leader选举(Leader Election)  ——  一种临时的角色,只存在于leader的选举阶段,某个节点想要变成leader,那么就发起投票请求,同时自己变成candidate。如果选举成功,则变为candidate,否则退回为follower
  • leader(领导者):所有对系统的修改都会先经过leader —— 负责Client交互和log复制,同一时刻系统中最多存在1个

  状态或者说角色的流转如下:

  在 Raft 中,问题分解为:领导选取、日志复制、安全和成员变化。复制状态机通过复制日志来实现:

  • 日志:每台机器保存一份日志,日志来自于客户端的请求,包含一系列的命令
  • 状态机:状态机会按顺序执行这些命令
  • 一致性模型:分布式环境下,保证多机的日志是一致的,这样回放到状态机中的状态是一致的

3、Raft 一致性算法

  Raft 通过选出一个leader来简化日志副本的管理,例如:日志项(log entry)只允许从leader流向follower。

  基于leader的方法,Raft算法可以分解成三个子问题:

(1)Leader election (领导选举):原来的leader挂掉后,必须选出一个新的leader

(2)Log replication (日志复制):leader从客户端接收日志,并复制到整个集群中

(3)Safety (安全性):如果有任意的server将日志项回放到状态机中了,那么其他的server只会回放相同的日志项

四、Leader election (领导选举)  ——  Raft 算法流程

  Raft 使用一种心跳机制来触发领导人选举。

  当服务器程序启动时,他们都是 follower(跟随者) 身份。如果一个跟随者在一段时间里没有接收到任何消息,也就是选举超时,然后他就会认为系统中没有可用的领导者,然后开始进行选举以选出新的领导者。

  要开始一次选举过程,follower 会给当前term加1并且转换成candidate状态。

  然后他会并行的向集群中的其他服务器节点发送请求投票的 RPCs 来给自己投票。

  候选人的状态维持直到发生以下任何一个条件发生的时候:

  • 他自己赢得了这次的选举

    • 如果这个节点赢得了半数以上的vote就会成为leader,每个节点会按照first-come-first-served的原则进行投票,并且一个term中只能投给一个节点, 这样就保证了一个term最多有一个节点赢得半数以上的vote。
    • 当一个节点赢得选举, 他会成为leader, 并且给所有节点发送这个信息, 这样所有节点都会回退成follower。
  • 其他的服务器成为领导者

    如果在等待选举期间,candidate接收到其他server要成为leader的RPC,分两种情况处理:

    • 如果leader的term大于或等于自身的term,那么改candidate 会转成follower 状态
    • 如果leader的term小于自身的term,那么会拒绝该 leader,并继续保持candidate 状态
  • 一段时间之后没有任何一个获胜的人

    • 有可能,很多follower同时变成candidate,导致没有candidate能获得大多数的选举,从而导致无法选出主。当这个情况发生时,每个candidate会超时,然后重新发增加term,发起新一轮选举RPC。需要注意的是,如果没有特别处理,可能出导致无限地重复选主的情况。

    • Raft采用随机定时器的方法来避免上述情况,每个candidate选择一个时间间隔内的随机值,例如150-300ms,采用这种机制,一般只有一个server会进入candidate状态,然后获得大多数server的选举,最后成为主。每个candidate在收到leader的心跳信息后会重启定时器,从而避免在leader正常工作时,会发生选举的情况。

  有些概念我们需要理解下:

1、Term

  Term的概念类比中国历史上的朝代更替,Raft 算法将时间划分成为任意不同长度的任期(term)。任期用连续的数字进行表示。每一个任期的开始都是一次选举(election),一个或多个候选人会试图成为领导人。如果一个候选人赢得了选举,它就会在该任期的剩余时间担任领导人。在某些情况下,选票会被瓜分,有可能没有选出领导人,那么,将会开始另一个任期,并且立刻开始下一次选举。Raft 算法保证在给定的一个任期最多只有一个领导人。

2、RPC

  Raft 算法中服务器节点之间通信使用远程过程调用(RPCs),并且基本的一致性算法只需要两种类型的 RPCs,为了在服务器之间传输快照增加了第三种 RPC。RPC有三种:

  • RequestVote RPC:候选人在选举期间发起
  • AppendEntries RPC:领导人发起的一种心跳机制,复制日志也在该命令中完成
  • InstallSnapshot RPC: 领导者使用该RPC来发送快照给太落后的追随者

 3、选举流程

(1)follower增加当前的term,转变为candidate。
(2)candidate投票给自己,并发送RequestVote RPC给集群中的其他服务器。
(3)收到RequestVote的服务器,在同一term中只会按照先到先得投票给至多一个candidate。且只会投票给log至少和自身一样新的candidate。

  candidate节点保持(2)的状态,直到下面三种情况中的一种发生。

  • 该节点赢得选举。即收到大多数的节点的投票。则其转变为leader状态。
  • 另一个服务器成为了leader。即收到了leader的合法心跳包(term值等于或大于当前自身term值)。则其转变为follower状态。
  • 一段时间后依然没有胜者。该种情况下会开启新一轮的选举。

  Raft中使用随机选举超时时间来解决当票数相同无法确定leader的问题。

五、Log replication (日志复制)

  日志复制(Log Replication)主要作用是用于保证节点的一致性,这阶段所做的操作也是为了保证一致性与高可用性。当Leader选举出来后便开始负责客户端的请求,所有事务(更新操作)请求都必须先经过Leader处理,日志复制(Log Replication)就是为了保证执行相同的操作序列所做的工作。

  在Raft中当接收到客户端的日志(事务请求)后先把该日志追加到本地的Log中,然后通过heartbeat把该Entry同步给其他Follower,Follower接收到日志后记录日志然后向Leader发送ACK,当Leader收到大多数(n/2+1)Follower的ACK信息后将该日志设置为已提交并追加到本地磁盘中,通知客户端并在下个heartbeat中Leader将通知所有的Follower将该日志存储在自己的本地磁盘中。

  当选出 leader 后,它会开始接受客户端请求,每个请求会带有一个指令,可以被回放到状态机中。leader 把指令追加成一个log entry,然后通过AppendEntries RPC并行的发送给其他的server,当该entry被多数派server复制后,leader 会把该entry回放到状态机中,然后把结果返回给客户端。

  当 follower 宕机或者运行较慢时,leader 会无限地重发AppendEntries给这些follower,直到所有的follower都复制了该log entry。

  Raft 的log replication保证以下性质(Log Matching Property):

  • 如果两个 log entry 有相同的 index 和 term,那么它们存储相同的指令

  • 如果两个 log entry 在两份不同的日志中,并且有相同的 index 和 term,那么它们之前的log entry是完全相同的

  其中特性一通过以下保证:

  • leader在一个特定的term和index下,只会创建一个log entry
  • log entry不会改变它们在日志中的位置

  特性二通过以下保证:

  • AppendEntries会做log entry的一致性检查,当发送一个AppendEntriesRPC时,leader会带上需要复制的log entry前一个log entry的(index, iterm)

  如果follower没有发现与它一样的log entry,那么它会拒绝接受新的log entry 这样就能保证特性二得以满足。

六、安全性 —— 选举限制

  在一些一致性算法中,即使一台server没有包含所有之前已提交的log entry,也能被选为主,这些算法需要把leader上缺失的日志从其他的server拷贝到leader上,这种方法会导致额外的复杂度。

  相对而言,raft使用一种更简单的方法,即它保证所有已提交的log entry都会在当前选举的leader上,因此,在raft算法中,日志只会从leader流向follower。

  为了实现上述目标,raft在选举中会保证,一个candidate只有得到大多数的server的选票之后,才能被选为主。得到大多数的选票表明,选举它的server中至少有一个server是拥有所有已经提交的log entry的,而leader的日志至少和follower的一样新,这样就保证了leader肯定有所有已提交的log entry。

七、时间和可用性

  领导人选举是 Raft 中对时间要求最为关键的方面。Raft 可以选举并维持一个稳定的领导人,只要系统满足下面的时间要求:广播时间(broadcastTime) << 选举超时时间(electionTimeout) << 平均故障间隔时间(MTBF)

  • 广播时间指的是从一个服务器并行的发送 RPCs 给集群中的其他服务器并接收响应的平均时间;

  • 选举超时时间就是选举的超时时间限制

  • 平均故障间隔时间就是对于一台服务器而言,两次故障之间的平均时间。

  选举超时时间要大于广播时间的原因是,防止跟随者因为还没收到领导者的心跳,而重新选主。

  选举超时时间要小于MTBF的原因是,防止选举时,能正常工作的server没有达到大多数。

  对于广播时间,一般在[0.5ms,20ms]之间,而平均故障间隔时间一般非常大,至少是按照月为单位。因此,一般选举超时时间一般选择范围为[10ms,500ms]。因此,当领导者挂掉后,能在较短时间内重新选主。

八、如何解决 split brain 问题

  分布式协议一个著名问题就是 split brain 问题。

  简单说,就是比如当你的 cluster 里面有两个结点,它们都知道在这个 cluster 里需要选举出一个 master。那么当它们两之间的通信完全没有问题的时候,就会达成共识,选出其中一个作为 master。但是如果它们之间的通信出了问题,那么两个结点都会觉得现在没有 master,所以每个都把自己选举成 master。于是 cluster 里面就会有两个 master。

  区块链的分叉其实类似分布式系统的split brain。

  一般来说,Zookeeper会默认设置:

  • zookeeper cluster的节点数目必须是奇数。
  • zookeeper 集群中必须超过半数节点(Majority)可用,整个集群才能对外可用。

  Majority 就是一种 Qunroms 的方式来支持Leader选举,可以防止 split brain出现。奇数个节点可以在相同容错能力的情况下节省资源。

参考文章:https://www.cnblogs.com/binyue/p/8647733.html

原文地址:https://www.cnblogs.com/goloving/p/14992133.html