ZAB协议概述和Zookeeper集群搭建

推荐阅读:

分布式一致性理论和一致性协议2PC、3PC

拜占庭将军问题和共识算法Paxos、Raft

Zookeeper概述

Zookeeper 为分布式应用提供了高效且可靠的分布式协调服务,提供了诸如统一命名服务、发布订阅、负载均衡、配置管理和分布式锁等分布式的基础服务。

设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。

可以保证以下特性:
+ 顺序一致性:从同一个客户端发起的事务请求,最终将会严格地按照其发起顺序被应用到 Zookeeper 中。
+ 原子性:要么集群中所有机器都成功应用了某一个事务,要么都没有应用。
+ 单一视图:无论客户端连接的是哪一个 Zookeeper 服务器,其看到的服务端数据模型都是一致性的
+ 可靠性:一旦服务端成功应用了某个事务,并完成对客户端的响应,那么该事务所引起
的服务端状态变更将会被一直保留下来。
+ 实时性:Zookeeper 能保证在一定的时间段内,客户端最终一定能够从服务端上读取到最新的数据状态。

ZAB协议

ZAB(zookeeper atomic broadcast)是Zookeeper采用的协议,是一种支持崩溃恢复的原子广播协议,基于multi paxos实现。

三种角色

  • leader
    leader负责处理集群的写请求,并发起投票,只有超过半数的节点同意后才会提交该写请求
  • follower
    处理读请求,响应结果。转发写请求到leader,在选举leader过程中参与投票
  • observer
    observer可以理解为没有投票权的follower,主要职责是协助follower处理读请求。那么当整个zk集群读请求负载很高时,为什么不增加follower节点呢?原因是增加follower节点会让leader在提出写请求提案时,需要半数以上的follower投票节点同意,这样会增加leader和follower的通信通信压力,降低写操作效率。

ZooKeeper使用单一主进程Leader用于处理客户端所有事务请求,即写请求。当服务器数据发生变更,集群采用ZAB原子广播协议,以事务提交proposal的形式广播到所有的副本进程,每一个事务分配一个全局的递增的事务编号xid。

若客户端提交的请求为读请求时,则接受请求的节点直接根据自己保存的数据响应。若是写请求,且当前节点不是leader,那么该节点就会将请求转发给leader,leader会以提案的方式广播此写请求,如果超过半数的节点同意写请求,则该写请求就会提交。leader会通知所有的订阅者同步数据。

ZAB的工作基本可以分为leader选举阶段和消息广播阶段:

leader选举

当服务启动或leader崩溃后,zk进入leader选举阶段,leader选出后,将完成leader和其他机器的数据同步,当大多数server完成和leader的同步后,该阶段结束。

每个节点有一个zxid:zxid一个是64位长度的Long类型,其中高32位表示纪元epoch,低32位表示事务标识xid。即zxid由两部分构成:epoch和xid。epoch类似于raft的term,每一个新的选举开启时都会生成一个新的epoch,新的leader产生,会更新所有的zkServer的zxid的epoch,xid是一个依次递增的事务编号。

启动过程

  • 每一个 server发出一个投票给集群中其他节点
  • 收到各个服务器的投票后,判断该投票有效性,比如是否是本轮投票,是否是looking状态
  • 处理投票, pk别人的投票和自己的投票 比较规则xid>myid “取大原则”
  • 统计是否超过半数的接受相同的选票
  • 确认 leader,改变服务器状态
  • 添加新 server,leader已经选举出来,只能以follower身份加入集群中

注意一个节点可以投多票,即每次收到竞选信息的时候都可以决定是否投票,而不是raft的先来先得。

崩溃恢复过程

leader 挂掉后,集群中其他follower会将状态从FOLLOWING变为LOOKING,重新进入leader选举

同上启动过程

消息广播

一旦Leader已经和多数的Follower进行了状态同步后,进入广播模式。进入广播模式后,如果有新加入的服务器,会自动从leader中同步数据。leader在接收客户端请求后,会生成事务提案广播给其他机器,有超过半数以上的follower同意该提议后,再提交事务。注意在ZAB的事务的二阶段提交中,移除了事务中断的逻辑,follower要么ack,要么放弃,leader无需等待所有的follower的ack。

  • leader 接受到消息后,消息通过全局唯一的64位自增事务id,zxid标识
  • leader 发送给follower的提案是有序的,leader会创建一个FIFO队列,将提案顺序写入队列中发送给follower
  • follower 接受到提案后,会比较提案zxid和本地事务日志最大的zxid,若提案zxid比本地事务id大,将提案记录到本地日志中,反馈ack给leader,否则拒绝
  • leader 接收到过半ack后,leader向所有的follower发送commit,通知每个follower执行本地事务

更多Raft对比ZAB相关可以参考:

Raft对比ZAB协议 - 乒乓狂魔 - OSCHINA

Zookeeper集群搭建

zookeeper下载:

wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.5.7/apache-zookeeper-3.5.7-bin.tar.gz

下载完成后解压:

tar -zxvf apache-zookeeper-3.5.7-bin.tar.gz

进入文件夹并创建一个data目录:

cd apache-zookeeper-3.5.7-bin
mkdir data

我们在单机使用三个zookeeper进程来搭建伪集群:

cd ..
mv apache-zookeeper-3.5.7-bin zookeeper-01
cp -r zookeeper-01 zookeeper-02
cp -r zookeeper-01 zookeeper-03

为每个zookeeper文件夹下的data文件夹新建一个myid文件,内容分别为1、2、3

cd zookeeper-01/data
vim myid

将每一个zookeeper文件夹下的conf/zoo_sample.cfg重命名为zoo.cfg,并修改内容:

mv zoo_sample.cfg zoo.cfg
vim zoo.cfg

配置文件中默认dataDir=/temp/zookeeper,修改为各自目录下的data文件夹,并将zookeeper02、zookeeper03的端口号修改为2182和2183(默认为2181)

# 安装的文件夹
dataDir=/root/zookeeper-02/data
clientPort=2182

并在末尾添加:

server.1=192.168.91.1:2881:3881
server.2=192.168.91.1:2882:3882
server.3=192.168.91.1:2883:3883

它的格式是:server.服务器ID=服务器IP地址:服务器之间通信端口:服务器之间投票选举端口

保存并退出,依次启动1、2、3:

bin/zkServer.sh start

按照ZAB的投票机制,2号主机将会成为leader:

root@DESKTOP-TTLFG6F:~/zookeeper-02# bin/zkServer.sh status
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /root/zookeeper-02/bin/../conf/zoo.cfg
Client port found: 2182. Client address: localhost.
Mode: leader

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/zab%e5%8d%8f%e8%ae%ae%e6%a6%82%e8%bf%b0%e5%92%8czookeeper%e9%9b%86%e7%be%a4%e6%90%ad%e5%bb%ba/

发表评论

电子邮件地址不会被公开。