zoukankan      html  css  js  c++  java
  • 浅析分布式一致性算法

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

    一、为什么需要一致性

    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

  • 相关阅读:
    Hadoop 集群安装(从节点安装配置)
    Hadoop 集群安装(主节点安装)
    少儿编程(2):简单的数学计算
    少儿编程(1):计算思维
    Web测试入门:Selenium+Chrome+Python+Mac OS
    我为什么建议:在软工实践作业中增加性能测试分析的任务?
    基于码云开展程序设计教学的自动判分方法和代码框架?
    数值计算 的bug:(理论)数学上等价,实际运行未必等价
    【Alpha】Daily Scrum Meeting总结
    【Alpha】Daily Scrum Meeting第十次
  • 原文地址:https://www.cnblogs.com/goloving/p/14992133.html
Copyright © 2011-2022 走看看