1、简介
Zookeeper是一个树形目录服务,是一个基于观察者模式设计的分布式、开源应用程序协调服务,可存储数据和接受注册。一旦数据发生变化,Zookeeper负责通知已注册的节点。
主要功能:配置管理、分布式锁、集群管理
架构如下:
- Zookeeper:一个leader和多个follower组成集群
- Zookeeper集群中有半数以上节点正常,即可提供服务,适合奇数台服务器。
- 全局数据一致:Zookeeper保存一份相同的副本。
- 更新请求顺序执行,来自同一个Client的请求按发送顺序执行。
- 数据更新原子性。
- 同步时间很快,能保证实时性。
- 数据结构
数据模型为树形结构,每个节点为ZNode,每个ZNode默认能存1MB,并可通过路径进行唯一标识。
2、下载安装(单机版)
下载地址:https://archive.apache.org/dist/zookeeper/zookeeper-3.5.7/
解压后修改conf文件夹下的配置文件,先修改配置文件名,将zoo-sample.cfg改为zoo.cfg,将否则启动报错
grep: /export/soft/zookeeper/apache-zookeeper-3.5.7-bin/bin/../conf/zoo.cfg: 没有那个文件或目录
之后创建Zookeeper数据存放文件夹zkData,并修改zoo.cfg
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/export/soft/zookeeper/apache-zookeeper-3.5.7-bin/zkData
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
启动Zookeeper
cd /export/soft/zookeeper/apache-zookeeper-3.5.7-bin/bin
./zkServer.sh start#启动命令
查看Zookeeper状态
./zkServer.sh status
启动客户端
./zkCli.sh
退出客户端
quit
停止zk服务
./zkServer.sh stop
3、配置参数含义
-
tickTime:通信心跳时间,单位ms
-
initLimit:
leader和follower初始连接能容忍的最多心跳数(tickTime的数量),即如果通信时间超过initLimit*tickTime的时间就是通信超时
-
syncLimit:同步通信时限,通信时间超过syncLimit*tickTime,就从列表中删除该节点
-
dataDir:保存Zookeeper中的数据目录
-
clientPort:客户端连接端口
4、集群安装、启动、停止
在/export/soft/zookeeper/apache-zookeeper-3.5.7-bin/zkData目录下新增myid文件,myid为服务器身份标识,三台机器分别为0,1,2并修改配置文件,增加如下配置:
server.0=hadoop100:2888:3888
server.1=hadoop101:2888:3888
server.2=hadoop102:2888:3888
含义:server.myid=服务器节点:follower与leader通信端口:重新选举通信端口。修改完成后进行分发。
集群启动:
三台服务器同时执行下面命令,并查看状态。
/export/soft/zookeeper/apache-zookeeper-3.5.7-bin/bin/zkServer.sh start
/export/soft/zookeeper/apache-zookeeper-3.5.7-bin/bin/zkServer.sh status
集群停止
/export/soft/zookeeper/apache-zookeeper-3.5.7-bin/bin/zkServer.sh stop
5、Zookeeper的leader选举原则
-
第一次启动选举
在启动没达到半数时,服务器处在looking状态,在启动达到半数以上后,myid最大的作为leader,后续启动的服务器都是follower
-
leader掉线重新选举
通过服务器id(SID)、事务id(ZXID)、leader任期代号(Epoch)进行选举
选举优先级:Epoch>ZXID>SID
6、客户端命令
使用远程客户端
./zkCli.sh -server hadoop102:2181
查看节点信息
[zk: hadoop102:2181(CONNECTED) 3] ls -s /
[zookeeper]cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = -1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1
创建节点
#不带序号
create /test "111"
#带序号
create -s /test2 "222"
获取节点值
get /test
修改节点值
set /test "333"
删除节点(只能删除叶子节点)
delete /test
7、节点类型
持久:客户端与服务端断开后,创建的节点不删除。其中,持久化顺序编号目录节点只是Zookeeper给该节点名称进行顺序编号
短暂:客户端与服务端断开后,创建的节点删除
8、监听器
监听步骤:
- 有main()线程
- 在main()线程中创建Zookeeper客户端,客户端创建两个线程分别负责通信和监听
- 通信线程将注册监听事件发送给Zookeeper
- 在Zookeeper的注册监听器列表中将注册的监听事件添加到列表中
- Zookeeper监听到变化,发消息给监听线程
- 监听线程调用process方法
常见的监听:监听节点数据变化、监听节点增减变化
注意:注册一次,监听只监听一次,后续变化不会通知。
创建数据监听
get -w /test
在节点数据改变后,监听到数据变化后会给出通知。
WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/test
创建路径监听
create /test/test1
路径变化后,监听到路径变化后会给出通知。
WATCHER::
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/test
9、java代码操作Zookeeper
-
添加maven
<dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.5.7</version> </dependency>
-
初始化客户端
private ZooKeeper zkClient; @Before public void init() throws IOException { String connectSring="192.168.132.102:2181"; int sessionTimeout=80000; zkClient = new ZooKeeper(connectSring, sessionTimeout, new Watcher() { public void process(WatchedEvent watchedEvent) { } }); }
-
创建节点
@Test public void create () throws KeeperException, InterruptedException { zkClient.create("/testJava", "11".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); }
-
获取子节点,只能监听一次
@Test public void getChild() throws KeeperException, InterruptedException { List<String> children = zkClient.getChildren("/", true); children.forEach((s)->{ System.out.println(s); }); }
-
持续监听
在初始化时,将事件写到process方法中,实现持续监听
public void init() throws IOException { String connectSring="192.168.132.102:2181"; int sessionTimeout=80000; zkClient = new ZooKeeper(connectSring, sessionTimeout, new Watcher() { public void process(WatchedEvent watchedEvent) { List<String> children = null; try { children = zkClient.getChildren("/", true); } catch (KeeperException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } children.forEach((s)->{ System.out.println(s); }); } }); }
-
判断节点存在
public void exist() throws KeeperException, InterruptedException { Stat stat = zkClient.exists("/testJava", true); System.out.println(stat); }