前言

ZooKeeper是一个提供高可用,一致性,高性能的保证读写顺序的存储系统。ZAB协议为ZooKeeper专门设计的一种支持数据一致性的原子广播协议。

演示环境

$ uname -a
Darwin 18.6. Darwin Kernel Version 18.6.: Thu Apr :: PDT ; root:xnu-4903.261.~/RELEASE_X86_64 x86_64

安装

brew cask install java
brew install zookeeper

配置

这里演示的是在同一台机器部署3个ZooKeeper进程的伪集群。

$ cat /usr/local/etc/zookeeper/zoo1.cfg
tickTime=
initLimit=
syncLimit=
dataDir=/usr/local/var/run/zookeeper/data1
clientPort=
server.=localhost::
server.=localhost::
server.=localhost::7888
$ echo "1" > /usr/local/var/run/zookeeper/data1/myid
  • tickTime ZooKeeper中使用的基本时间单元,以毫秒为单位,默认是2000。它用来调节心跳和超时。
  • initLimit 默认值是10,即tickTime属性值的10倍。表示允许follower连接并同步到leader的最大时间。如果ZooKeeper管理的数据量很大的话可以增加这个值。
  • syncLimit 默认值是5,即tickTime属性值的5倍。表示lead和follower进行心跳检测的最大延迟时间。如果在设置的时间内follower无法于leader进行通信,那么follower将会被丢弃。
  • dataDir ZooKeeper用来存储内存数据库快照的目录,并且除非指定其他目录,否则数据库更新的事务日志也会存储在该目录。可以配置dataLogDir指定ZooKeeper事务日志的存储目录。
  • clientPort 服务器监听客户端连接的端口,默认是2181。
  • server.id = host:port1:port2 集群模式中用于感知其他机器,每一行代表一个ZooKeeper实例配置。id被成为Server ID用来表示实例在集群中的序号。同时需要将每个实例的ID写入dataDir的myid文件中。port1用于数据同步。port2用于选举。

集群中第2个实例的配置为:

$ cat /usr/local/etc/zookeeper/zoo2.cfg
tickTime=
initLimit=
syncLimit=
dataDir=/usr/local/var/run/zookeeper/data2
clientPort=
server.=localhost::
server.=localhost::
server.=localhost::
$ cat /usr/local/var/run/zookeeper/data2/myid

集群中第3个示例的配置为:

$ cat /usr/local/etc/zookeeper/zoo3.cfg
tickTime=
initLimit=
syncLimit=
dataDir=/usr/local/var/run/zookeeper/data3
clientPort=
server.=localhost::
server.=localhost::
server.=localhost::
$ cat /usr/local/var/run/zookeeper/data3/myid

启动集群:

$ zkServer start /usr/local/etc/zookeeper/zoo1.cfg
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo1.cfg
Starting zookeeper ... STARTED
$ zkServer start /usr/local/etc/zookeeper/zoo2.cfg
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo2.cfg
Starting zookeeper ... STARTED
$ zkServer start /usr/local/etc/zookeeper/zoo3.cfg
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo3.cfg
Starting zookeeper ... STARTED
$ zkServer status /usr/local/etc/zookeeper/zoo1.cfg
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo1.cfg
Mode: follower
$ zkServer status /usr/local/etc/zookeeper/zoo2.cfg
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo2.cfg
Mode: leader
$ zkServer status /usr/local/etc/zookeeper/zoo3.cfg
ZooKeeper JMX enabled by default
Using config: /usr/local/etc/zookeeper/zoo3.cfg
Mode: follower

从上面的状态检查可以看出,第二实例是leader,其他两个实例是follower。

操作

下面我将演示在集群中读写节点。

$ zkCli -server localhost:
Connecting to localhost:
Welcome to ZooKeeper!
JLine support is enabled WATCHER:: WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:(CONNECTED) ] create /test "i am test"
Created /test
[zk: localhost:(CONNECTED) ] get /test
i am test
cZxid = 0x200000002
ctime = Tue Jul :: CST
mZxid = 0x200000002
mtime = Tue Jul :: CST
pZxid = 0x200000002
cversion =
dataVersion =
aclVersion =
ephemeralOwner = 0x0
dataLength =
numChildren =

在实例2中创建/test节点,接下来在实例3中也能读取到该节点,说明ZooKeeper集群数据的一致性。

ZooKeeper语义保证

ZooKeeper简单高效,同时提供以下语义保证,从而使我们可以利用这些特性提供复杂的服务:

  • 顺序性:客户端发起的更新请求会按发送顺序被应用到ZooKeeper上。
  • 原子性:更新操作要么成功要么失败,不会出现中间状态。
  • 可靠性:一个更新操作一旦被接受即不会意外丢失,除非被其他更新操作覆盖。
  • 最终一致性:写操作最终(而非立即)会对客户端可见。

ZooKeeper Watch 机制

所有对ZooKeeper的读操作都可以附带一个Watch。一旦相应的数据有变化,该Watch即被触发。

Watch有以下特点:

  • 主动推送:Watch被触发时,由ZooKeeper服务器主动将更新推送给客户端,而不需要客户端轮询。
  • 一次性:数据变化时Watch只会被触发一次。如果客户端想得到后续更新的通知,必须要在Watch被触发后重新再注册一个Watch。
  • 顺序性:如果多个更新触发了多个Watch,那Watch被触发的顺序与更新的顺序一致。
  • 可见性:如果一个客户端在读请求中附带Watch,Watch被触发的同时再次读取数据,客户端在得到Watch消息之前肯定不可能看到更新后的数据。换句话说,更新通知先于更新结果。

ZAB协议

为了保证写操作的一致性与可用性,ZooKeeper在paxos的基础上设计了一种名为原子广播(ZAB)的支持崩溃恢复的一致性协议。基于该协议,ZooKeeper实现了一种主从模式的系统架构来保持集群中各个副本之间的数据一致性。

根据ZAB协议,所有的写操作都必须通过leader来完成,leader写入本地日志后再复制到所有的follower节点。如果客户端对follower/observer发起写请求,follower/observer会将请求转发到leader,然后由leader处理完成后再将结果转发回follower/observer发送给客户端。

ZAB协议分为广播模式崩溃恢复模式

leader处理写请求(广播模式)的步骤为:

1.leader为事务请求生成唯一的事务ID(ZXID),ZAB协议会将每个事务Proposal按照ZXID的先后顺序来进行排序和处理。

2.将Proposal发送给follower并等待follower回复ACK。

3.leader收到超过半数的ACK(leader默认对自己有一个ACK)后向所有的follower/observer发送commit,同时leader自身也会完成commit。

4.将处理结果返回给客户端。

上述过程成为ZooKeeper的两阶段提交。

崩溃恢复:

当leader实例宕机崩溃,或者因为网络原因导致其与过半的follower都失去联系,那么就会进入崩溃恢复阶段。

leader宕机或者与过半的follower失联都会导致leader重新选举(选举算法文章后面会介绍)。选举结束后会紧着进入数据崩溃恢复,以保证数据一致性,也就是数据同步。需要保证已经commit的事务被所有服务器都提交,同时需要丢弃那些只在leader服务器提交的事务。所以选出来的新leader要拥有集群中最高编号的ZXID。在新的leader选举出来后就会进行数据同步工作,leader会将那些没有被follower同步的事务以Proposal消息的形式发送给follower,并在每个Proposal消息后面紧跟着发送一个commit消息,表示该事务已经被提交。然后follower服务器会将同步过来的事务Proposal都成功应用到本地数据库。

ZXID是个64位的无符号整形,高32位是epoch,代表leader选择周期,低32位是累加计数,每一轮选举后该计数会清零。leader服务器没产生一个事务,ZXID的低32位就会加一,没完成一次leader选举,就会将ZXID的高32位加一。这样做是为了保证新leader生成的ZXID肯定是大于旧leader之前产生的ZXID。

领导选举算法

服务器状态:

  • LOOKING 不确定Leader状态。该状态下的服务器认为当前集群中没有Leader,会发起Leader选举。
  • FOLLOWING 跟随者状态。表明当前服务器角色是Follower,并且它知道Leader是谁。
  • LEADING 领导者状态。表明当前服务器状态是leader,它会维护与Follower间的心跳。
  • OBSERVING 观察者状态。表明当前服务器角色是Observer,与Follower不同是不参与选举,也不参与集群写操作的投票。

选票数据结构:

每个服务器在进行领导者选举是,会发送如下关键信息:

  • logicClock 每个服务器都会维护一个自增的整数,名为logicClock,它表示这是该服务器第几轮发起的投票。
  • state 表示该服务器当前的状态。
  • self_id 当前服务器的myid
  • self_zxid 当前服务器上所保存的数据的最大zxid
  • vote_id 被推举的服务器的myid
  • vote_zxid 被推举的服务器上所保存的数据的最大zxid

(快速领导者选举算法)选票PK:

选票PK是基于(logicClock,self_id, self_zxid) 与 (vote_logicClock, vote_self_id, vote_self_zxid)对比:
先比较logicClock,如果相等再比较zxid,如果zxid相等,再比较myid。最后如果vote大于自身,则改票,也投vote。

总结

文章一开始演示ZooKeeper的部署和操作给读者一个直观感受,然后介绍了ZooKeeper的ZAB协议和领导者选举原理。

参考

https://cwiki.apache.org/confluence/display/ZOOKEEPER/ProjectDescription

https://dbaplus.cn/news-141-1875-1.html

ZooKeeper和ZAB协议的更多相关文章

  1. zookeeper的ZAB协议

    ZAB协议概述 ZooKeeper并没有完全采用Paxos算法,而是使用了一种称为ZooKeeper Atomic Broadcast(ZAB,zookeeper原子消息广播协议)的协议作为其数据一致 ...

  2. 简述 zookeeper 基于 Zab 协议实现选主及事务提交

    Zab 协议:zookeeper 基于 Paxos 协议的改进协议 zookeeper atomic broadcast 原子广播协议. zookeeper 基于 Zab 协议实现选主及事务提交. 一 ...

  3. ZooKeeper之ZAB协议

    ZooKeeper为高可用的一致性协调框架,自然的ZooKeeper也有着一致性算法的实现,ZooKeeper使用的是ZAB协议作为数据一致性的算法,ZAB(ZooKeeper Atomic Broa ...

  4. zookeeper核心-zab协议-《每日五分钟搞定大数据》

    上篇文章<paxos与一致性>说到zab是在paxos的基础上做了重要的改造,解决了一系列的问题,这一篇我们就来说下这个zab. zab协议的全称是ZooKeeper Atomic Bro ...

  5. 三:ZooKeeper的ZAB协议

    一:ZAB协议概述--->ZooKeeper并没有完全采用Paxos算法,而是使用了一种称为ZooKeeper Atomic Broadcast(ZAB,zookeeper原子消息广播协议)的协 ...

  6. 2. ZooKeeper的ZAB协议。

    转自:https://blog.csdn.net/en_joker/article/details/78662880 ZooKeeper并没有完全采用Paxos算法,而是使用了一种称为ZooKeepe ...

  7. 【5】Zookeeper的ZAB协议

    一.ZAB协议(原子消息广播协议)   ZAB(Zookeeper Atomic Broadcast)协议是Zookeeper用来保证其数据一致性的核心算法,是一种支持崩溃恢复的原子广播协议.基于此协 ...

  8. 分布式专题(二)——Zookeeper的ZAB协议介绍

  9. zookeeper 入门系列-理论基础 – zab 协议

    上一章讨论了paxos算法,把paxos推到一个很高的位置.但是,paxos有没有什么问题呢?实际上,paxos还是有其自身的缺点的: 1. 活锁问题.在base-paxos算法中,不存在leader ...

随机推荐

  1. OSX - Mac OS 10.12后Caps lock(大写键)无法使用的解决办法

    我在OSX的虚拟机中安装了windows 7 操作系统,但是发现在win7下,大写键不起作用,通过下面方面搞定了! ▲打开设置中的键盘选项,并切换至输入源选项标签, ▲取消勾选“使用大写锁定键来回切换 ...

  2. 安装nginx + nginx-gridfs + mongodb

    1.安装依赖包 yum -y install pcre-devel openssl-devel zlib-devel git gcc gcc-c++ git clone https://github. ...

  3. 记一次至今懵逼的bug

      <update id="falseDeleteBatchByPKArr" parameterType="java.lang.String"> U ...

  4. 日常工具集和技巧分享(Linux向)

    好用的软件/终端 命令别名 ip切换 imgcat 终端查看图片 autojump 目录快捷跳转 titan 密码记录工具 tldr man 的简单版,在线查询linux命令示例 ssh 别名/免密码 ...

  5. ReentrantReadWriteLock中的锁降级

    锁降级指的是写锁降级为读锁. 因为读锁与读锁之间不互斥,如果是写锁与读锁或者是写锁与写锁就会互斥,所以由写锁变为读锁就降级了. 如果当前线程拥有写锁,然后将其释放,最后再获取读锁,这种并不能称之为锁降 ...

  6. HDU - 5823:color II (状压DP 反演DP)

    题意:给定连通图,求出连通图的所有子图的颜色数. 一个图的颜色数,指最少的颜色数,给图染色,使得有边相邻的点之间颜色不同. 思路:首先想法是DFS枚举,然后计算颜色,发现对于给定图,求颜色不会求? 毕 ...

  7. 1、Python简介与Python安装

    一.Python简介: Python 是一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言. Python的创始人为吉多·范罗苏姆(Guido van Rossum)少数几个不秃头的语言创始 ...

  8. 《团队作业第三、四周》五阿哥小组Scrum 冲刺阶段---Day4

    <团队作业第三.四周>五阿哥小组Scrum 冲刺阶段---Day3 一.项目燃尽图 二.项目进展 20182310周烔今日进展: 主要任务一览:聊天软件主界面 20182330魏冰妍今日进 ...

  9. computed配合watch监听对象数据

  10. react编写规范之组件组件的内容编写顺序

    static 开头的类属性,如 defaultProps.propTypes. 构造函数,constructor. getter/setter(还不了解的同学可以暂时忽略). 组件生命周期. _ 开头 ...