Apache Zookeeper

Apache Zookeeper

Apache Zookeeper Website: https://zookeeper.apache.org

alt text

Zookeeper简介

Zookeeper是一个分布式协调调度框架,主要用来解决分布式集群中应用系统的一致性问题

  • Zookeeper本质上是一个分布式的小文件存储系统。提供基于类似于文件系统的目录树方式的数据存储,并且可以对树中的节点进行有效管理;
  • Zookeeper提供给客户端监控存储在ZK内部数据的功能,从而可以达到基于数据的集群管理。诸如:统一命名服务(Dubbo)、分布式配置管理(Solr的配置集中管理)、分布式消息队列(sub/pub)、分布式锁、分布式协调等功能。

ZK的架构构成

Leader

  • Zookeeper集群工作的核心角色;
  • 集群内部各个服务器的调度者;
  • 事务请求(写操作)的唯一调度和处理者,保证集群事务处理的顺序性;对于create, setData, Delete等有写操作的请求,则需要统一转发给Leader处理,Leader需要决定编号、执行操作,这个过程称为一个事务。

Follower

  • 处理客户端非事务(读操作)请求;
  • 转发事务请求给Leader;
  • 参与集群Leader选举投票2n - 1 台可以做集群投票。

Observer

  • 观察者角色,观察Zookeeper集群的最新状态变化并将这些状态同步过来,其对于非事务请求可以进行独立处理,对于事务请求,则会转发给Leader服务器进行处理;
  • 不会参与任何形式的投票只提供非事务服务,通常用于在不影响集群事务处理能力的前提下提升集群的非事务处理能力。增加了集群并发的读请求

Zookeeper特点

  1. Zookeeper:一个领导者(Leader),多个跟随者(Follower)组成的集群;
  2. Leader负责进行投票的发起和决议,更新系统状态;
  3. Follower用于接收客户请求并向客户端返回结果,在选举Leader过程中参与投票;
  4. 集群中只有半数以上节点存活,Zookeeper集群就能正常服务;
  5. 全局数据一致:每个server保存一份相同的数据副本,Client无论连接到哪个server,数据都是一致的;
  6. 更新请求顺序进行;
  7. 数据更新原子性,一次数据更新要么成功,要么失败。

ZK环境搭建

ZK的搭建方式

ZK安装方式有三种,单机模式和集群模式以及伪集群模式。

  • 单机模式:Zookeeper只允许在一台服务器上,适合测试环境;
  • 伪集群模式:就是在一台服务器上运行多个zk实例;
  • 集群模式:zk运行于一个集群上,适合生产环境,这个计算集群被称为一个“集合体”

ZK单机模式

Getting Started Guide

官网下载网址下载最新版本3.7.0,具体部署步骤详见Getting Started Guide

常用命令

  1. 启动命令

    bin/zkServer.sh start
    
  2. 查看启动状态

    bin/zkServer.sh status
    
  3. 停止命令

       bin/zkServer.sh stop
    

ZK数据结构与监听机制

Zookeeper数据模型Znode

在Zookeeper中,数据信息被保存在一个个数据节点上,这些节点被称为ZNode。ZNode是ZK中最小的数据单元,在ZNode下面又可以再挂ZNode,这样一层层下去就形成了一个层次化命名空间ZNode树,我们称为ZNode Tree,它采用了类似文件系统的层级树状结构进行管理。见下图示例:

Data Model

在zk中,每一个数据节点都是一个ZNode,ZNode的节点路径标识方式和Unix文件系统路径非常相似,都是由一系列使用斜杠(/)进行分割的路径表示,开发人员可以向这个节点写入数据,也可以在这个节点下面创建子节点。

ZNode类型

ZK节点类型可以分为三大类:

  • 持久性节点(Persistent):节点被创建后会一直存在服务器,直到删除操作主动清除;

  • 临时性节点(Ephemeral):它的生命周期和客户端会话绑在一起,客户端会话结束,节点会被删除掉。与持久性节点不同的是,临时节点不能创建子节点;

  • 顺序性节点(Sequential):实质就是在创建节点的时候,会在节点名后面加上一个数字后缀,来表示其顺序。

在开发中创建节点的时候通过组合可以生成以下四种节点类型:持久节点持久顺序节点临时节点临时顺序节点

事务ID

在ZK中,事务是指能够改变ZK服务器状态的操作,包括数据节点创建、删除、内容更新等操作。对于每一个事务请求,ZK都会为其分配一个全局唯一的事务ID,用ZXID来表示,通常是一个64位的数字。每一个ZXID对应一次更新操作,从这些ZXID中可以间接识别出ZK处理这些更新操作请求的全局顺序。

ZNode的状态信息

[zk: localhost:2181(CONNECTED) 5] get -s /zk-persist
123
cZxid = 0x8
ctime = Mon Jan 03 17:09:50 CST 2022
mZxid = 0x8
mtime = Mon Jan 03 17:09:50 CST 2022
pZxid = 0x8
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
field description
czxid 创建znode的zxid
mzxid 最近一次修改znode的zxid(创建、删除、set直系子节点、set自身节点都会计数)
pzxid 最近一次修改子节点的zxid(创建、删除直系子节点都会计数,set子节点不会计数)
ctime 创建znode的时间,单位毫秒
mtime 最近一次修改znode的时间,单位毫秒
version 修改znode的次数
cversion 修改子节点的次数(创建、删除直系子节点都会计数,set子节点不会计数)
aversion 该znode的ACL修改次数
ephemeralOwner 临时znode节点的session id,如果不是临时节点,值为0
dataLength znode携带的数据长度,单位字节
numChildren 直系子节点的数量(不会递归计算孙节点)

Watcher机制

zk使用Watcher机制实现分布式数据的发布/订阅功能。zk允许客户端向服务端注册一个Watcher监听,当服务端的一些指定事件触发了这个Watcher,那么zk就会向指定的客户端发送一个事件通知来实现分布式的通知功能。整个Watcher注册与通知过程如图所示:

zk Watcher

ZK的Watcher机制主要包括:客户端线程客户端WatcherManagerZookeeper服务器三部分。

具体工作流程为:

  1. 客户端在向zk服务器注册的同时,会将Watcher对象存储在客户端的WatchManager当中;
  2. 当ZK服务器触发Watcher事件后,会向客户端发送通知;
  3. 客户端线程从WatcherManager中取出对应的Watcher对象来执行回调逻辑。

ZK的基本使用

zk命令行操作

通过zkClient进入zk客户端命令行

./zkcli.sh  # 连接本地的zk服务器
./zkcli.sh -server ip:port  # 连接指定的服务器

帮助命令

[zk: localhost:2181(CONNECTED) 3] help
ZooKeeper -server host:port -client-configuration properties-file cmd args
	addWatch [-m mode] path # optional mode is one of [PERSISTENT, PERSISTENT_RECURSIVE] - default is PERSISTENT_RECURSIVE
	addauth scheme auth
	close
	config [-c] [-w] [-s]
	connect host:port
	create [-s] [-e] [-c] [-t ttl] path [data] [acl]
	delete [-v version] path
	deleteall path [-b batch size]
	delquota [-n|-b|-N|-B] path
	get [-s] [-w] path
	getAcl [-s] path
	getAllChildrenNumber path
	getEphemerals path
	history
	listquota path
	ls [-s] [-w] [-R] path
	printwatches on|off
	quit

创建节点

使用create命令创建一个zk节点,如:

create [-s] [-e] path data
  • -s代表创建一个顺序节点;
  • -e代表创建一个临时节点;
  • 若不指定,则创建一个持久节点。
  1. 创建顺序节点

    [zk: localhost:2181(CONNECTED) 5] create -s /zk-test 123
    Created /zk-test0000000000
    

    执行完后,就在根节点下创建了一个叫做/zk-test的节点,该节点内容就是123,同时可以看到创建的zk-test节点后面添加了一串数字以示区别。

  2. 创建临时节点

    [zk: localhost:2181(CONNECTED) 7] create -e /zk-temp 123
    Created /zk-temp
    [zk: localhost:2181(CONNECTED) 8] ls /
    [zk-temp, zk-test0000000000, zookeeper]
    

    临时节点在客户端会话结束后,就会自动删除,下面使用quit命令退出客户端

    [zk: localhost:2181(CONNECTED) 9] quit
    
    WATCHER::
    
    WatchedEvent state:Closed type:None path:null
    2022-01-03 17:06:16,947 [myid:] - INFO  [main:ZooKeeper@1232] - Session: 0x10014703c2b0001 closed
    2022-01-03 17:06:16,948 [myid:] - INFO  [main-EventThread:ClientCnxn$EventThread@570] - EventThread shut down for session: 0x10014703c2b0001
    2022-01-03 17:06:16,949 [myid:] - ERROR [main:ServiceUtils@42] - Exiting JVM with code 0
    

    再次使用客户端连接服务端,并使用ls /命令查看根目录的节点

    [zk: localhost:2181(CONNECTED) 0] ls /
    [zk-test0000000000, zookeeper]
    

    可以看到根目录下已经不存在zk-temp临时节点了。

  3. 创建永久节点

    [zk: localhost:2181(CONNECTED) 1] create /zk-persist 123
    Created /zk-persist
    [zk: localhost:2181(CONNECTED) 2] ls /
    [zk-persist, zk-test0000000000, zookeeper]
    

    可以看到永久节点不用与顺序节点,不会自动在后面添加一串数据。

读取节点

与读取相关的命令有:

  • ls命令:可以列出zk指定节点下的所有子节点,但只能查看指定节点下的第一级的所有子节点;
  • get命令:可以获取zk指定节点的数据内容和属性信息。

若获取根节点下面的所有子节点,使用ls /命令即可

[zk: localhost:2181(CONNECTED) 2] ls /
[zk-persist, zk-test0000000000, zookeeper]

若想获取节点的数据内容和属性,可使用get path命令

[zk: localhost:2181(CONNECTED) 3] get /zk-persist
123
# -s 表示包含ZNode状态信息
[zk: localhost:2181(CONNECTED) 5] get -s /zk-persist
123
cZxid = 0x8
ctime = Mon Jan 03 17:09:50 CST 2022
mZxid = 0x8
mtime = Mon Jan 03 17:09:50 CST 2022
pZxid = 0x8
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0

更新节点

使用set命令,可以更新指定节点的数据内容,用户如下:

$ set [-s] [-v version] path data

其中data就是要更新的新内容,version表示数据版本。在zk中,节点的数据是有版本概念的,这个参数用于指定本次更新操作时基于ZNode的哪一个数据版本进行的。

[zk: localhost:2181(CONNECTED) 6] set /zk-persist 666
[zk: localhost:2181(CONNECTED) 7] get -s /zk-persist
666
cZxid = 0x8
ctime = Mon Jan 03 17:09:50 CST 2022
mZxid = 0x9
mtime = Mon Jan 03 17:24:56 CST 2022
pZxid = 0x8
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0

删除节点

使用delete命令可以删除zk上的指定节点,用法如下:

delete [-v version] path

NOTE: 若删除节点存在子节点时,那么无法直接删除该节点,必须先删除子节点,再删除父节点。

posted @ 2022-01-03 19:59  LukeBlog  阅读(813)  评论(0编辑  收藏  举报