1.概述
ZooKeeper是一种为分布式应用所设计的高可用、高性能且一致的开源协调服务,它提供了一项基本服务:分布式锁服务。由于ZooKeeper的开源特性,后来我们的开发者在分布式锁的基础上,摸索了出了其他的使用方法:配置维护、组服务、分布式消息队列、分布式通知/协调等。
设计目标
简单的数据结构:共享的数型结构,类似文件系统,存储于内存。
可以构建集群:避免单点故障,3-5台机器就可以组成集群,超过半数正常工作就能提供服务。
顺序访问:对于每个读请求,zk会分配一个全局唯一的递增编号,利用这个特性可以实现高级协调服务。
高性能:基于内存操作,服务于非事物请求,适用于读操作为主的业务场景。
2.安装
可去官网下载一个稳定的版本,然后进行安装:www.apache.org/dyn/closer.…
解压后在zookeeper的conf目录下创建配置文件zoo.cfg,里面的配置信息可参考统计目录下的zoo_sample.cfg文件,我们这里配置为:
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/opt/zookeeper-data/
clientPort=2181
复制代码
tickTime:指定了ZooKeeper的基本时间单位(以毫秒为单位);
initLimit:指定了启动zookeeper时,zookeeper实例中的随从实例同步到领导实例的初始化连接时间限制,超出时间限制则连接失败(以tickTime为时间单位);
syncLimit:指定了zookeeper正常运行时,主从节点之间同步数据的时间限制,若超过这个时间限制,那么随从实例将会被丢弃;
dataDir:zookeeper存放数据的目录;
clientPort:用于连接客户端的端口。
在配置完响应的配置后,进入到bin目录下可以直接通过 bin 目录下的zkServer.sh脚本执行相应的操作:
1. 启动zk服务sh zkServer.sh start 或者./zkServer.sh start.
2. 查看zk服务状态sh zkServer.sh status
3. 停止当前zk服务sh zkServer.sh stop
4. 重启服务sh zkServer.sh restart
复制代码
客户端可以使用./zkClient.sh -server 127.0.0.1:2181连接到当前zookeeper服务器。客户端命令行工具的一些简单操作如下:
1.ls:获取路径下的节点信息,注意此路径为绝对路径,类似于linux的ls命令。如ls /zookeeper;
2.create:创建节点,其中-s为顺序充点,-e临时节点。如create /zookeeper/node1"test_create";
3.get:获取节点信息,注意节点的路径皆为绝对路径,也就是说必要要从/(根路径)开始。如get /;
4.set:设置节点的数据。如set /zookeeper "hello world";
5.delete:删除节点,不能递归删除,如果存在子节点则删除失败。
6.rmr:递归删除
7.quit:退出客户端
8.help:帮助命令
....
复制代码
3.Zookeeper的存储模型
zookeeper的师徒结构和标准的Unix文件系统类似,每个节点称为“数据节点”或Znode,每个Znode可以存储数据同时可以挂载子节点,因此可以称之为“树”。
特性:1.在Zookeeper中,znode是一个跟Unix文件系统路径相似的节点,可以往这个节点存储或获取数据
2.通过客户端可对znode进行增删改查的操作,还可以注册watcher监控znode的变化。
Znode
1.Znode是Zookeeper中数据的最小单元,每个Znode上都可以保存数据,同时还可以挂载子节点,znode之间的层级关系就像文件系统的目录结构一样,zookeeper将全部的数据存储在内存中以此来提高服务器吞吐量、减少延迟的目的。
2.Znode有三种类型,Znode的类型在创建时确定并且不能修改。
临时(EPHEMERAL):在创建临时Znode的客户端会话结束时,服务器会将临时节点删除。临时节点不能有子节点(即使是临时子节点)。虽然每个临时Znode都会绑定一个特定的客户端会话,但是它们对所有客户端都是可见的
持久(PERSISTENT):节点一旦被创建,会一直存在与服务器上,Zookeeper规定所有非叶子节点必须是持久化节点
顺序(SEQUENTIAL):如果在创建Znode时设置了顺序标识,那么该Znode名称之后便会附加一个值,这个值由一个单调递增的计数器(由父节点维护)所添加
3.临时节点在两种情况下会被删除
当创建Znode的客户端的会话因超时或者主动关闭而终止时(不是TCP连接断开) 当某个客户端(不一定是临时Znode的创建者)主动删除该节点时
4.每个数据节点除了存储数据内容之外,还存储了数据节点本身的一些状态信息。Znode的状态(Stat)信息
序号 | 属性 | 结数据构 | 描述 |
1 | czxid | long | 节点被创建的Zxid值 |
2 | mzxid | long | 节点被修改的Zxid值 |
3 | pzxid | long | 子节点最有一次被修改时的事务ID |
4 | ctime | long | 节点被创建的时间 |
5 | mtime | long | 节点最后一次被修改的时间 |
6 | versoin | long | 节点被修改的版本号 |
7 | cversion | long | 节点的所拥有子节点被修改的版本号 |
8 | aversion | long | 节点的ACL被修改的版本号 |
9 | emphemeralOwner | long | 如果此节点为临时节点,那么它的值为这个节点 拥有者的会话ID;否则,它的值为0 |
10 | dataLength | int | 节点数据域的长度 |
11 | numChildren | int | 节点拥有的子节点个数 |
对于持久节点和临时节点,同一个znode下,节点的名称是唯一的! —— 实现分布式锁的基础
4.Watch监听机制
客户端可以在znode上设置watcher,监听znode的变化。Znode发生变化(Znode本身的增加,删除,修改,以及子Znode的变化)可以通过Watch机制通知到客户端。
·两类watch
1.dara watch监听数据变更
2.child watch监听子节点变化
·触发事件
Created event:
Enabled with a call to exists.
Deleted event:
Enabled with a call to exists, getData, and getChildren.
Changed event:
Enabled with a call to exists and getData.
Child event:
Enabled with a call to getChildren.
复制代码
·特性
1.一次性触发。 客户端在Znode设置了Watch时,如果Znode内容发生改变,那么客户端就会获得Watch事件。例如:客户端设置getData("/znode1", true)后,如果/znode1发生改变或者删除,那么客户端就会得到一个/znode1的Watch事件,但是/znode1再次发生变化,那客户端是无法收到Watch事件的,除非客户端设置了新的Watch。
2.有序性。Watch事件是异步发送到Client。Zookeeper可以保证客户端发送过去的更新顺序是有序的。例如:某个Znode没有设置watcher,那么客户端对这个Znode设置Watcher发送到集群之前,该客户端是感知不到该Znode任何的改变情况的。换个角度来解释:由于Watch有一次性触发的特点,所以在服务器端没有Watcher的情况下,Znode的任何变更就不会通知到客户端。不过,即使某个Znode设置了Watcher,且在Znode有变化的情况下通知到了客户端,但是在客户端接收到这个变化事件,但是还没有再次设置Watcher之前,如果其他客户端对该Znode做了修改,这种情况下,Znode第二次的变化客户端是无法收到通知的。这可能是由于网络延迟或者是其他因素导致,所以我们使用Zookeeper不能期望能够监控到节点每次的变化。Zookeeper只能保证最终的一致性,而无法保证强一致性。