Zookeeper的安装&使用

目标

  1. 什么是分布式
  2. 为什么选择Zookeeper
  3. Zookeeper的设计目标
  4. Zookeeper的数据模型
  5. 安装Zookeeper
  6. 单节点配置Zookeeper
  7. 多节点配置Zookeeper
  8. Zookeeper的常用命令
  9. Zookeeper的监听
  10. Zookeeper四字命令

什么是分布式

分布式系统

分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。分布式系统的出现是为了用廉价的、普通的机器完成单个计算机无法完成的计算、存储任务。其目的是利用更多的机器,处理更多的数据

分布式协调技术

分布式系统的出现带来了分布式协调的问题,也就是我们如何对分布式系统中的进程进行调度,假设我们在某一台机器上面挂载了一个资源,然后其他物理分布的进程都要竞争这个资源,但是我们又不希望他们同时访问,这时候就需要一个协调器,让他们有序的来访问在这个资源。这个协调器就是我们经常提到的那个,比如说”进程-1”在使用该资源的时候,会先去获得锁,”进程1”获得锁以后会对该资源保持独占,这样其他进程就无法访问该资源,”进程1”用完该资源以后就将锁释放掉,让其他进程来获得锁,那么通过这个锁机制,我们就能保证了分布式系统中多个进程能够有序的访问该临界资源。那么我们把这个分布式环境下的这个锁叫作分布式锁。分布式锁也就是我们分布式协调技术实现的核心内容。

为什么选择zookeeper

ZooKeeper是一种为分布式应用所设计的高可用、高性能且一致的开源协调服务,它提供了一项基本服务:分布式锁服务。由于ZooKeeper的开源特性,后来我们的开发者在分布式锁的基础上,摸索了出了其他的使用方法:配置维护、组服务、分布式消息队列分布式通知/协调等。

ZooKeeper在实现这些服务时,首先它设计一种新的数据结构——Znode,然后在该数据结构的基础上定义了一些原语,也就是一些关于该数据结构的一些操作。有了这些数据结构和原语还不够,因为我们的ZooKeeper是工作在一个分布式的环境下,我们的服务是通过消息以网络的形式发送给我们的分布式应用程序,所以还需要一个通知机制——Watcher机制。那么总结一下,ZooKeeper所提供的服务主要是通过:数据结构+原语+watcher机制,三个部分来实现的。

ZooKeeper性能上的特点决定了它能够用在大型的、分布式的系统当中。从可靠性方面来说,它并不会因为一个节点的错误而崩溃。除此之外,它严格的序列访问控制意味着复杂的控制原语可以应用在客户端上。ZooKeeper在一致性、可用性、容错性的保证,也是ZooKeeper的成功之处,它获得的一切成功都与它采用的协议——Zab协议是密不可分的,这些内容将会在后面介绍。

Zookeeper的设计目标

ZooKeeper 很简单。ZooKeeper允许分布式进程通过共享的层次命名空间相互协调,该命名空间的组织类似于标准文件系统。名称空间由数据寄存器组成——用ZooKeeper的说法称为znodes——这些寄存器类似于文件和目录。与典型的用于存储的文件系统不同,ZooKeeper数据保存在内存中,这意味着ZooKeeper可以实现高吞吐量和低延迟数。

ZooKeeper实现非常重视高性能、高可用性和严格有序的访问。ZooKeeper的性能方面意味着它可以用于大型分布式系统。可靠性方面使它不会成为单点故障。严格的排序意味着复杂的同步原语可以在客户端实现。

ZooKeeper 是复制。与它所协调的分布式进程一样,ZooKeeper本身也打算在一组称为集合的主机上进行复制。

Zookeeper集群部署

组成ZooKeeper服务的服务器必须相互了解。它们在内存中维护状态映像,以及持久存储中的事务日志和快照。只要大多数服务器可用,ZooKeeper服务就可用。

客户端连接到单个ZooKeeper服务器。客户端维护一个TCP连接,通过它发送请求、获取响应、获取监视事件和发送心跳。如果到服务器的TCP连接中断,客户机将连接到另一台服务器。

ZooKeeper是有序的。ZooKeeper用一个数字来标记每个更新,这个数字反映了所有ZooKeeper事务的顺序。后续操作可以使用该顺序来实现更高级别的抽象,比如同步原语。

ZooKeeper很快。在“以读取为主”的工作负载中,它的速度特别快。ZooKeeper应用程序运行在数千台机器上,当读操作比写操作更常见时,它的性能最好,比率约为10:1。

Zookeeper的数据模型

ZooKeeper拥有一个层次的命名空间,这个和标准的文件系统非常相似,如下图所示。

ZooKeeper数据模型与文件系统目录树

从图中我们可以看出ZooKeeper的数据模型,在结构上和标准文件系统的非常相似,都是采用这种树形层次结构,ZooKeeper树中的每个节点被称为—Znode。和文件系统的目录树一样,ZooKeeper树中的每个节点可以拥有子节点。但也有不同之处:

  1. 引用方式

    Zonde通过路径引用,如同Unix中的文件路径。路径必须是绝对的,因此他们必须由斜杠字符来开头。除此以外,他们必须是唯一的,也就是说每一个路径只有一个表示,因此这些路径不能改变。在ZooKeeper中,路径由Unicode字符串组成,并且有一些限制。字符串”/zookeeper”用以保存管理信息,比如关键配额信息。

  2. Znode结构

    ZooKeeper命名空间中的Znode,兼具文件和目录两种特点。既像文件一样维护着数据、元信息、ACL、时间戳等数据结构,又像目录一样可以作为路径标识的一部分。图中的每个节点称为一个Znode。 每个Znode由3部分组成:

    • stat:此为状态信息, 描述该Znode的版本, 权限等信息

    • data:与该Znode关联的数据

    • children:该Znode下的子节点

    ZooKeeper虽然可以关联一些数据,但并没有被设计为常规的数据库或者大数据存储,相反的是,它用来管理调度数据,比如分布式应用中的配置文件信息、状态信息、汇集位置等等。这些数据的共同特性就是它们都是很小的数据,通常以KB为大小单位。ZooKeeper的服务器和客户端都被设计为严格检查并限制每个Znode的数据大小至多1M,但常规使用中应该远小于此值。

  3. 数据访问

    ZooKeeper中的每个节点存储的数据要被原子性的操作。也就是说读操作将获取与节点相关的所有数据,写操作也将替换掉节点的所有数据。另外,每一个节点都拥有自己的ACL(访问控制列表),这个列表规定了用户的权限,即限定了特定用户对目标节点可以执行的操作。

  4. 节点类型

    ZooKeeper中的节点有两种,分别为临时节点永久节点。节点的类型在创建时即被确定,并且不能改变。

    临时节点:

    • 该节点的生命周期依赖于创建它们的会话。一旦会话(Session)结束,临时节点将被自动删除,当然可以也可以手动删除。虽然每个临时的Znode都会绑定到一个客户端会话,但他们对所有的客户端还是可见的。另外,ZooKeeper的临时节点不允许拥有子节点。

    永久节点:

    • 该节点的生命周期不依赖于会话,并且只有在客户端显示执行删除操作的时候,他们才能被删除。
  5. 顺序节点

    当创建Znode的时候,用户可以请求在ZooKeeper的路径结尾添加一个递增的计数。这个计数对于此节点的父节点来说是唯一的,它的格式为”%10d”(10位数字,没有数值的数位用0补充,例如”0000000001”)。当计数值大于232-1时,计数器将溢出。

  6. 观察

    客户端可以在节点上设置watch,我们称之为监视器。当节点状态发生改变时(Znode的增、删、改)将会触发watch所对应的操作。当watch被触发时,ZooKeeper将会向客户端发送且仅发送一条通知,因为watch只能被触发一次,这样可以减少网络流量。

安装Zookeeper

  1. 下载源码包()

    http://archive.cloudera.com/cdh5/cdh/5/zookeeper-3.4.5-cdh5.16.2.tar.gz
  2. 编译

    yum install ant	//zk的编译不是使用maven的,而是使用ant
    ant package

    需要注意两个坑:

    1. 需要指定jdk为1.7
    2. 远端仓库连不上,需要改路径
  3. 配置环境变量

单节点配置Zookeeper

  1. 修改zoo.cfg文件(需要从zoo_sample.cfg复制一份)
  2. 修改dataDir路径,默认放在/tmp目录下,dataDir主要用于保存Zookeeper中的数据
  3. 启动服务端 bin/zkServer.sh start
  4. 启动客户端 bin/zkCli.sh

多节点配置Zookeeper

  1. 修改zoo.cfg文件(需要从zoo_sample.cfg复制一份)

  2. 修改dataDir路径,默认放在/tmp目录下,dataDir主要用于保存Zookeeper中的数据

  3. 在zoo.cfg文件中配置集群的id、主机和端口号,集群共享内容

    server.2=hadoop102:2888:3888
    server.3=hadoop103:2888:3888
    server.4=hadoop104:2888:3888

    server.A=B:C:D
    A:标识第几号服务器,有一个myid要与之对应
    B:服务器的地址
    C:follower与leader通信的端口
    D:选举leader时的端口

  4. 在dataDir指定的路径下创建myid文件,添加与之对应的服务器编号,即编号A,集群唯一内容,Zookeeper启动时读取此文件,拿到里面的数据与zoo.cfg里面的配置信息比较从而判断到底是哪个server。

  5. 启动集群服务端 bin/zkServer.sh start

  6. 启动集群客户端 ,工作中客户端连接集群命令:

    ./zkCli.sh -server hadoop102:2181,hadoop103:2181,hadoop104:2181

Zookeeper的常用命令

stat 	状态
set 修改
ls 查看
ls2 ls+get
delete 删除
rmr 递归删除
get 得到
create 创建
  1. stat path [watch]:数据的状态

    [zk: localhost:2181(CONNECTED) 1] stat /tunan

    cZxid = 0x21	//节点的id号
    ctime = Mon Mar 02 15:27:36 CST 2020 //节点的创建时间
    mZxid = 0x32 //节点修改的id号
    mtime = Mon Mar 02 15:36:45 CST 2020 //节点修改的时间
    pZxid = 0x38 //最后更新的子节点的id
    cversion = 9 //节点所拥有的子节点的被修改的版本号
    dataVersion = 1 //节点数据版本号
    aclVersion = 0 //节点所拥有的ACL版本号
    ephemeralOwner = 0x0 //特殊标记 0x0: 永久节点
    dataLength = 3 //数据的长度
    numChildren = 5 //子节点的个数
  2. set path data [version]:修改数据

    [zk: localhost:2181(CONNECTED) 5] set /tunan/aaa 123456

    cZxid = 0x31	//这是一个子节点的id跟上面的父节点的id不同
    ctime = Mon Mar 02 15:35:31 CST 2020 //子节点的创建时间
    mZxid = 0x3a //子节点的修改id
    mtime = Tue Mar 03 11:28:06 CST 2020 //子节点的修改时间
    pZxid = 0x31 //最后更新的子节点的id,我们现在更新的是这个节点,所以对应cZxid
    cversion = 0 //节点所拥有的子节点的被修改的版本号,明显和父节点不同
    dataVersion = 1 //数据被修改过了,所以版本号变了
    aclVersion = 0 //节点所拥有的ACL版本号
    ephemeralOwner = 0x0 //特殊标记 0x0: 永久节点
    dataLength = 6 //数据的长度
    numChildren = 0 //子节点的个数
  3. ls path [watch]:查看节点

    [zk: localhost:2181(CONNECTED) 8] ls /tunan

    [aaa, ccc, bbb, eee, ddd]
  4. ls2 path [watch]:查看并获取节点内容,等同于get

    [zk: localhost:2181(CONNECTED) 9] ls2 /tunan

    [aaa, ccc, bbb, eee, ddd]	//节点的数据内容
  5. delete path [version]:删除节点

    [zk: localhost:2181(CONNECTED) 10] delete /tunan/aaa
    [zk: localhost:2181(CONNECTED) 11] ls /tunan

    [ccc, bbb, eee, ddd]
  6. rmr path:递归删除节点

    [zk: localhost:2181(CONNECTED) 12] rmr /tunan/ccc
    [zk: localhost:2181(CONNECTED) 13] ls /tunan


    [bbb, eee, ddd]
  7. get path [watch]:获取节点内容,等同于ls2

    [zk: localhost:2181(CONNECTED) 14] get /tunan/bbb

    222
  8. create [-s] [-e] path data acl:创建节点

    -s:顺序创建

    [zk: localhost:2181(CONNECTED) 0] create -s /tunan/bbb 12345

    Created /tunan/bbb0000000007

    [zk: localhost:2181(CONNECTED) 1] create -s /tunan/bbb 12345

    Created /tunan/bbb0000000008

    -e:临时创建

    [zk: localhost:2181(CONNECTED) 5] create -e /tunan/fff 12345

    Created /tunan/fff

Zookeeper的监听

  1. watch概述

    ZooKeeper可以为所有的读操作设置watch,这些读操作包括:exists()、getChildren()及getData()。watch事件是一次性的触发器,当watch的对象状态发生改变时,将会触发此对象上watch所对应的事件。watch事件将被异步地发送给客户端,并且ZooKeeper为watch机制提供了有序的一致性保证。理论上,客户端接收watch事件的时间要快于其看到watch对象状态变化的时间。

  2. watch类型

    ZooKeeper所管理的watch可以分为两类:

    • 数据watch(data watches):getDataexists负责设置数据watch

    • 孩子watch(child watches):getChildren负责设置孩子watch

    我们可以通过操作返回的数据来设置不同的watch:

    • getData和exists:
    • getChildren:返回孩子列表

    因此

    1. 一个成功的setData操作将触发Znode的数据watch

    2. 一个成功的create操作将触发Znode的数据watch以及孩子watch

    3. 一个成功的delete操作将触发Znode的数据watch以及孩子watch

  3. watch注册与处触发

    图 6.1 watch设置操作及相应的触发器如图下图所示:

    img

    1. exists操作上的watch,在被监视的Znode创建删除数据更新时被触发。
    2. getData操作上的watch,在被监视的Znode删除数据更新时被触发。在被创建时不能被触发,因为只有
    3. getChildren操作上的watch,在被监视的Znode的子节点创建删除,或是这个Znode自身被删除时被触发。可以通过查看watch事件类型来区分是Znode,还是他的子节点被删除:NodeDelete表示Znode被删除,NodeDeletedChanged表示子节点被删除。

    Watch由客户端所连接的ZooKeeper服务器在本地维护,因此watch可以非常容易地设置、管理和分派。当客户端连接到一个新的服务器时,任何的会话事件都将可能触发watch。另外,当从服务器断开连接的时候,watch将不会被接收。但是,当一个客户端重新建立连接的时候,任何先前注册过的watch都会被重新注册。

  4. 需要注意的几点

    Zookeeper的watch实际上要处理两类事件:

    • 连接状态事件(type=None, path=null)

      这类事件不需要注册,也不需要我们连续触发,我们只要处理就行了。

    • 节点事件

      节点的建立,删除,数据的修改。它是one time trigger,我们需要不停的注册触发,还可能发生事件丢失的情况。

    上面2类事件都在Watch中处理,也就是重载的process(Event event)

    节点事件的触发,通过函数exists,getData或getChildren来处理这类函数,有双重作用:

    1. 注册触发事件
    2. 函数本身的功能

    函数的本身的功能又可以用异步的回调函数来实现,重载processResult()过程中处理函数本身的的功能。

  5. 命令行操作

    监听创建节点(stat命令)

    stat /xiaoqi watch

    [zk: localhost:2181(CONNECTED) 13] create /xiaoqi 111

    WATCHER::

    WatchedEvent state:SyncConnected type:NodeCreated path:/xiaoqi
    Created /xiaoqi

    监听修改节点(stat命令)

    stat /xiaoqi watch

    [zk: localhost:2181(CONNECTED) 16] set /xiaoqi 1234

    WATCHER::

    WatchedEvent state:SyncConnected type:NodeDataChanged path:/xiaoqi

    监听删除节点(stat命令)

    stat /xiaoqi watch

    [zk: localhost:2181(CONNECTED) 20] delete /xiaoqi

    WATCHER::

    WatchedEvent state:SyncConnected type:NodeDeleted path:/xiaoqi

    监听父节点删除子节点(ls命令)

    ls /xiaoqi watch

    [zk: localhost:2181(CONNECTED) 29] create /xiaoqi/aaa 111

    WATCHER::

    WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/xiaoqi

    监听父节点创建子节点(ls命令)

    ls /xiaoqi watch

    [zk: localhost:2181(CONNECTED) 31] delete /xiaoqi/aaa

    WATCHER::

    WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/xiaoqi

Zookeeper四字命令

官网

无须启动zk客户端,直接在命令行输入echo {}| nc localhost 2181 即可

stat: 列出服务器和连接的客户机的简要信息。

echo stat | nc localhost 2181

Zookeeper version: 3.4.5-cdh5.16.2--1, built on 06/03/2019 10:40 GMT
Clients: //客户端
/127.0.0.1:58056[0](queued=0,recved=1,sent=0)
/127.0.0.1:57020[1](queued=0,recved=288,sent=296)

Latency min/avg/max: 0/0/20
Received: 454 //接收
Sent: 461 //发送
Connections: 2 //连接数
Outstanding: 0
Zxid: 0x53
Mode: standalone //模式
Node count: 17 //节点数

ruok: 测试服务器是否在非错误状态下运行。

echo ruok | nc localhost 2181

imok

dump: 列出未完成的会话和临时节点。这只对leader有效。

echo dump | nc localhost 2181

SessionTracker dump:
Session Sets (3):
0 expire at Tue Mar 03 12:29:46 CST 2020:
0 expire at Tue Mar 03 12:29:56 CST 2020:
1 expire at Tue Mar 03 12:30:06 CST 2020:
0x1709e65d9b00001
ephemeral nodes dump:
Sessions with Ephemerals (1):
0x1709e65d9b00001:
/tunan/fff //临时节点

conf: 打印关于服务配置的详细信息。

echo conf | nc localhost 2181

clientPort=2181	//端口
dataDir=/home/hadoop/tmp/zookeeper/version-2 //数据目录
dataLogDir=/home/hadoop/tmp/zookeeper/version-2 //日志目录
tickTime=2000 //心跳时间,单位毫秒
maxClientCnxns=60 //最大连接数
minSessionTimeout=4000 //最小的超时时间
maxSessionTimeout=40000 //最大的超时时间
serverId=0 //服务器的id

envi: 打印出服务环境的细节

echo envi | nc localhost 2181

Environment:
zookeeper.version=3.4.5-cdh5.16.2--1, built on 06/03/2019 10:40 GMT
host.name=aliyun
java.version=1.8.0_144
java.vendor=Oracle Corporation
java.home=/usr/java/jdk1.8.0_144/jre
java.class.path=/home/hadoop/app/zookeeper/bin/../build/classes:/home/hadoop/app/zookeeper/bin/../build/lib/*.jar:/home/hadoop/app/zookeeper/bin/../share/zookeeper/zookeeper-3.4.5-cdh5.16.2.jar:/home/hadoop/app/zookeeper/bin/../share/zookeeper/slf4j-log4j12-1.7.5.jar:/home/hadoop/app/zookeeper/bin/../share/zookeeper/slf4j-api-1.7.5.jar:/home/hadoop/app/zookeeper/bin/../share/zookeeper/netty-3.10.5.Final.jar:/home/hadoop/app/zookeeper/bin/../share/zookeeper/log4j-1.2.16.jar:/home/hadoop/app/zookeeper/bin/../share/zookeeper/jline-2.11.jar:/home/hadoop/app/zookeeper/bin/../src/java/lib/*.jar:/home/hadoop/app/zookeeper/bin/../conf:
java.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
java.io.tmpdir=/tmp
java.compiler=<NA>
os.name=Linux
os.arch=amd64
os.version=3.10.0-514.26.2.el7.x86_64
user.name=hadoop
user.home=/home/hadoop
user.dir=/home/hadoop/app/zookeeper-3.4.5-cdh5.16.2/bin

mntr: 输出可用于监视集群健康状况的变量列表。

echo mntr | nc localhost 2181

zk_version	3.4.5-cdh5.16.2--1, built on 06/03/2019 10:40 GMT
zk_avg_latency 0
zk_max_latency 20
zk_min_latency 0
zk_packets_received 494
zk_packets_sent 501
zk_num_alive_connections 2
zk_outstanding_requests 0
zk_server_state standalone
zk_znode_count 17
zk_watch_count 1
zk_ephemerals_count 1
zk_approximate_data_size 253
zk_open_file_descriptor_count 27
zk_max_file_descriptor_count 65535
zk_fsync_threshold_exceed_count 0

wchs: 按会话列出关于服务器监视的详细信息。

echo wchs | nc localhost 2181

1 connections watching 1 paths
Total watches:1
Author: Tunan
Link: http://yerias.github.io/2020/03/02/zookeeper/1/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.