赞
踩
https://zhuanlan.zhihu.com/p/130332285
为了解决以上两个问题,就出现了一致性算法。
Paxos算法中的三种角色,包括Proposer,Acceptor,Learners。
事务编号 Zxid(事务请求计数器+ epoch)
在 ZAB ( ZooKeeper Atomic Broadcast , ZooKeeper 原子消息广播协议) 协议的事务编号 Zxid设计中, Zxid 是一个 64 位的数字,其中低 32 位是一个简单的单调递增的计数器, 针对客户端每一个事务请求,计数器加 1;而高 32 位则代表 Leader 周期 epoch 的编号, 每个当选产生一个新的 Leader 服务器,就会从这个 Leader 服务器上取出其本地日志中最大事务的 ZXID,并从中读取epoch 值,然后加 1,以此作为新的 epoch,并将低 32 位从 0 开始计数。Zxid(Transaction id) 类似于 RDBMS 中的事务 ID,用于标识一次更新操作的 Proposal(提议)
ID。为了保证顺序性,该 zkid 必须单调递增。
epoch
epoch:可以理解为当前集群所处的年代或者周期,每个 leader 就像皇帝,都有自己的年号,所以每次改朝换代, leader 变更之后,都会在前一个年代的基础上加 1。这样就算旧的 leader 崩溃恢复之后,也没有人听他的了,因为 follower 只听从当前年代的 leader 的命令。
Zab 协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步) 。当整个服务框架在启动过程中或者在领导者崩溃后, Zab 就进入了恢复模式选举产生新的Leader服务器。当领导者被选举出来,且过半的 Server 完成了和 leader 的状态同步以后,恢复模式就结束了。状态同步保证了 leader 和 Server 具有相同的系统状态。
当有新的server加入到集群时,此时集群中已经存在一个Leader服务器在负责进行消息广播,那么新加入的服务器会自动进入数据恢复模式,找到Leader服务器,并与其进行数据同步,然后一起参与到消息广播流程中去。
Discovery(发现阶段) : 在这个阶段, followers 跟准 leader 进行通信,同步 followers最近接收的事务提议。这个阶段的主要目的是发现当前大多数节点接收的最新提议,并且准 leader生成新的 epoch,让 followers 接受,更新它们的 accepted Epoch。
一个 follower 只会连接一个 leader, 如果有一个节点 f 认为另一个 follower p 是 leader, f在尝试连接 p 时会被拒绝, f 被拒绝之后,就会进入重新选举阶段。
Synchronization(同步阶段) : 同步阶段主要是利用 leader 前一阶段获得的最新提议历史,同步集群中所有的副本。 只有当 大多数节点都同步完成,准 leader 才会成为真正的 leader。follower 只会接收 zxid 比自己的 lastZxid 大的提议。
Broadcast(广播阶段) : 到了这个阶段, Zookeeper 集群才能正式对外提供事务服务,并且 leader 可以进行消息广播。同时如果有新的节点加入,还需要对新节点进行同步。
ZAB 提交事务并不像 2PC 一样需要全部 follower 都 ACK, 只需要得到超过半数的节点的 ACK 就可以了。
协议的 Java 版本实现跟上面的定义有些不同,选举阶段使用的是 Fast Leader Election(FLE),
它包含了 选举的发现职责。因为 FLE 会选举拥有最新提议历史的节点作为 leader,这样就省去了
发现最新提议的步骤。实际的实现将 发现阶段 和 同步合并为 Recovery Phase(恢复阶段)。所
以, ZAB 的实现只有三个阶段: Fast Leader Election; Recovery Phase; Broadcast Phase。
每个 sever 首先给自己投票, 然后用自己的选票和其他 sever 选票对比, 权重大的胜出,使用权重较大的更新自身选票箱。 具体选举过程如下:
目前有 5 台服务器,每台服务器均没有数据,它们的编号分别是 1,2,3,4,5,按编号依次启动,它们的选择举过程如下:
9. 服务器 1 启动,给自己投票,然后发投票信息,由于其它机器还没有启动所以它收不到反馈信息,服务器 1 的状态一直属于 Looking。
10. 服务器 2 启动,给自己投票,同时与之前启动的服务器 1 交换结果,由于服务器 2 的编号大所以服务器 2 胜出,但此时投票数没有大于半数,所以两个服务器的状态依然是LOOKING。
11. 服务器 3 启动,给自己投票,同时与之前启动的服务器 1,2 交换信息,由于服务器 3 的编号最大所以服务器 3 胜出,此时投票数正好大于半数,所以服务器 3 成为领导者,服务器1,2 成为小弟。
12. 服务器 4 启动,给自己投票,同时与之前启动的服务器 1,2,3 交换信息,尽管服务器 4 的编号大,但之前服务器 3 已经胜出,所以服务器 4 只能成为小弟。
13. 服务器 5 启动,后面的逻辑同服务器 4 成为小弟
与Paxos 不同Raft 强调的是易懂(Understandability),Raft 和Paxos 一样只要保证n/2+1 节点正常就能够提供服务;raft 把算法流程分为三个子问题:选举(Leader election)、日志复制(Log replication)、安全性(Safety)三个子问题。
Raft把集群中的节点分为三种状态,Leader、Follower、Candidate,理所当然每种状态负责的任务也是不一样的,Raft运行时提供服务的时候只存在Leader与Follower两种状态。
Leader(领导者-日志管理)
负责日志的同步管理,处理来自客户端的请求,与Follower保持这HeartBeat的联系。
Follower(追随者-日志同步)
刚启动时所有节点为Follower 状态,响应Leader 的日志同步请求,响应Candidate 的请求,把请求到Follower的事务转发给Leader。
Candidate(候选者-负责选票)
负责选票投票,Raft刚启动时由一个节点从Follower转为Candidate发起选举,选举出Leader后从Candidate转为Leader状态。
在Raft 中使用了一个可以理解为周期(第几届、任期)的概念,用Term 作为一个周期,每个Term 都是一个连续递增的编号,每一轮选举都是一个Term 周期,在一个Term 中只能产生一个Leader;当某节点收到的请求中Term 比当前Term 小时则拒绝该请求。
Raft 的选举由定时器来触发,每个节点的选举定时器时间都是不一样的,开始时状态都为Follower 某个节点定时器触发选举后Term 递增,状态由Follower 转为Candidate,向其他节点发起RequestVote RPC 请求,这时候有三种可能的情况发生:
在一个Term 期间每个节点只能投票一次,所以当有多个Candidate 存在时就会出现每个Candidate 发起的选举都存在接收到的投票数都不过半的问题,这时每个Candidate 都将Term递增、重启定时器并重新发起选举,由于每个节点中定时器的时间都是随机的,所以就不会多次存在有多个Candidate 同时发起投票的问题。
在Raft 中当接收到客户端的日志(事务请求)后先把该日志追加到本地的Log 中,然后通过heartbeat 把该Entry 同步给其他Follower,Follower 接收到日志后记录日志然后向Leader 发送ACK,当Leader 收到大多数(n/2+1)Follower 的ACK 信息后将该日志设置为已提交并追加到本地磁盘中,通知客户端并在下个heartbeat 中Leader 将通知所有的Follower 将该日志存储在自己的本地磁盘中。
https://zhuanlan.zhihu.com/p/107939861
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。