Zookeeper是一个开源的分布式的,为分布式框架提供协调服务的Apache项目。
Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper就将负责通知已经在Zookeeper.上注册的那些观察者做出相应的反应。
ZooKeeper数据模型的结构与Unix文件系统很类似,整体上可以看作是一棵树,每个节点称做一个ZNode。每一个ZNode默认能够存储1MB的数据,每个ZNode都可以通过其路径唯一标识。
提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等。
在分布式环境下,经常需要对应用/服务进行统一命名, 便于识别。例如: IP不容易记住,而域名容易记住。
1、分布式环境下,配置文件同步非常常见。
(1)一般要求一个集群中,所有节点的配置信息是一致的,比如Kafka集群。
(2)对配置文件修改后,希望能够快速同步到各个节点上。
2、配置管理可交由ZooKeeper实现。
(1)可将配置信息写入ZooKeeper 上的一个Znode。
(2)各个客户端服务器监听这个Znode。
(3) 一旦Znode中的数据被修改,ZooKeeper将通知各个客户端服务器。
1、分布式环境中,实时掌握每个节点的状态是必要的。
(1)可根据节点实时状态做出一-些调整。
2、ZooK eeper可以实现实时监控节点状态变化
(1) 可将节点信息写入ZooKeeper.上的一 个ZNode。
(2)监听这个ZNode可获取它的实时状态变化。
在Zookeeper中记录每台服务器的访问数,让访问数最少的服务器去处理最新的客户端请求。
https://zookeeper.apache.org/
mkdir -p /usr/zookeeper
cd /usr/zookeeper
tar -zxvf /usr/zookeeper/zookeeper-3.4.10.tar.gz -C /usr/zookeeper
cd /usr/zookeeper/zookeeper-3.4.10
mkdir zkdata
mkdir zkdatalog
进入zookeeper配置文件夹conf,将zoo_sample.cfg文件拷贝一份命名为zoo.cfg,Zookeeper 在启动时会找这个文件作为默认配置文件。
cd /usr/zookeeper/zookeeper-3.4.10/conf/
mv zoo_sample.cfg zoo.cfg
vim zoo.cfg
#对zoo.cfg文件配置如下:(在master执行)
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/zookeeper/zookeeper-3.4.10/zkdata
clientPort=2181
dataLogDir=/usr/zookeeper/zookeeper-3.4.10/zkdatalog
server.1=master:2888:3888
server.2=slave1:2888:3888
server.3=slave2:2888:3888
cd /usr/zookeeper/zookeeper-3.4.10/zkdata
vim myid
以上已经在主节点master上配置完成ZooKeeper,现在可以将该配置好的安装文件远程拷贝到集群中的各个结点对应的目录下:(在master执行)
scp -r /usr/zookeeper root@slave1:/usr/
scp -r /usr/zookeeper root@slave2:/usr/
cd /usr/zookeeper/zookeeper-3.4.10/zkdata
vim myid
vi /etc/profile
#set zookeeper environment
export ZOOKEEPER_HOME=/usr/zookeeper/zookeeper-3.4.10
PATH=$PATH:$ZOOKEEPER_HOME/bin
source /etc/profile
开启服务:bin/zkServer.sh start
查看状态:bin/zkServer.sh status
通过上面状态查询结果可见,一个节点是Leader,其余的结点是Follower。至此,zookeeper安装成功。
Zookeeper中的配置文件zoo.cfg中参数含义解读如下:
通信心跳时间,Zookeeper服务 器与客户端心跳时间,单位毫秒
LF初始通信时限
Leader和Follower初始连接时能容忍的最多心跳数(tickTime的数量)
LF同步通信时限
Leader和Follower之间通信时间如果超过syncLimit * tick Time,Leader认为Follwer死掉,从服务器列表中删除Follwer。
保存Zookeeper中 的数据
注意:默认的tmp目录,容易被Linux系统定期删除,所以一般不用默认的tmp目录。
客户端连接端口,通常不做修改。
[root@master bin]# sh zkCli.sh -server master:2181
命令基本语法 | 功能描述 |
---|---|
help | 显示所有操作命令 |
ls path | 使用 ls 命令来查看znode的子节点【可监听】 -w 监听子节点变化 -s 附加次级信息 |
create | 普通创建子节点 -s 含有序列 -e 临时(重启或者超时小时) |
get path | 获得节点的值【可监听】-w 监听节点内容变化 -e附加次级信息 |
set | 设置节点的具体值 |
stat | 查看节点信息 |
delete | 删除节点 |
deleteall | 递归删除节点 |
ls /
ls -s /
(1) czxid: 创建节点的事务zxid
每次修改ZooKeeper状态都会产生一个ZooKeeper事务ID。事务ID是ZooKeeper中所有修改总的次序。每次修改都有唯一的zxid,如果zxid小于zxid2,那么zxid在zxid2之前发生。
(2) ctime
znode 被创建的毫秒数(从1970年开始)
(3) mzxid
znode最后更新的事务zxid
(4) mtime
znode 最后修改的毫秒数(从1970年开始)
(5) pZxid
znode最后更新的子节点zxid
(6)cversion
znode 子节点变化号,znode, 子节点修改次数
(7) dataversion
znode 数据变化号
(8) aclVersion
znode 访问控制列表的变化号
(9) ephemeralOwner
如果是临时节点,这个是znode拥有者的session id。如果不是临时节点则是0。
(10) dataI ength
znode的数据长度
(11)numChildren
znode 子节点数量
持久(Persistent):客户端和服务器端断开连接后,创建的节点不删除
短暂(Ephemeral):客户端和服务器端断开连接后,创建的节点自己删除
[zk: master:2181(CONNECTED) 15] create /sanguo "yu zai"
create /sanguo/shuguo "dian dian"
获取节点中内容的值
get /sanguo
get /sanguo/shuguo
create -s /sanguo/weiguo/ "zhang liao"
quit
连接客户端
sh zkCli.sh -server master:2181
查看节点数据
ls /sanguo/weiguo
数据并未删除
create -e /sanguo/wuguo "zouiyu"
create -e -s /sanguo/wuguo "zouiyu3"
退出客户端
quit
连接客户端
sh zkCli.sh -server master:2181
查看临时节点数据
ls /sanguo
数据消失。
set /sanguo/weiguo "simayi"
客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、节点删除、子目录节点增加删除)时,ZooKeeper. 会通知客户端。监听机制保证 ZooKeeper 保存的任何的数据的任何改变都能快速的响应到监听了该节点的应用程序。
(1)首先要有一个main()线程
(2)在main线程中创建Zookeeper客户端 ,这时就会创建两个线程,一个负责网络连接通信(connet) ,-个负责监听(listener) 。
(3)通过connect线程将注册的监听事件发送给Zookeeper。
(4)在Zookeeper的注册监听器列表中将注册的监听事件添加到列表中。
(5)Zookeeper监 听到有数据或路径变化,就会将这个消息发送给listener线程。
(6)listener线程内部调用了process()方法。
(1)监听节点数据的变化
get path [watch]
(2)监听子节点增减的变化
ls path [watch]
① 启动三个节点的客户端
sh zkCli.sh -server master:2181
sh zkCli.sh -server slave1:2181
sh zkCli.sh -server slave2:2181
②在slave2节点上监控sanguo的数据值
查看数据值
get /sanguo
监控三国
get /sanguo -w
③在slave1节点上修改sanguo的数据
修改数据
set /sanguo "xisi"
slave2节点会监测的数据异常
④再次在slave1节点上修改sanguo的数据
修改数据
set /sanguo "yangfeiyan"
此时数据已经改变,但slave2的不会监测提醒
注意:在slave1再多次修改/sanguo的值,slave2上不会再收到监听。因为注册一次,只能监听一次。想再次监听,需要再次注册。
在slave2注册监听
ls /sanguo -w
create /sanguo/jinguo "simayi"
slave2监听到异常
注意:节点的路径变化,也是注册一次,生效一次。想多次生效,就需要多次注册。
(适用于删除子节点)
delete /sanguo/jinguo
(其节点与子节点都会删除)
deleteall /sanguo/shuguo
stat /sanguo
前提:保证hadoop102、hadoop103、 hadoop104 服务器上Zookeeper集群服务端启动。
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.5.7</version>
</dependency>
</dependencies>
需要在项目的src/main/resources目录下,新建一个文件,命名为“log4j.properties”,在文件中填入。
log4j.rootLogger=INFO,stdout
1og4j.appender.stdout=org.apache.log4j.ConsoleAppender
1og4i.appender.stdout.layout=org.apache.1og4j.PatternLayout
loq4j.appender.stdout.layout.ConversionPattern=%d%p[%c]-%m%n
1og4i.appender.logfile=org.apache.1og4j.FileAppender
log4j.appender.logfile.File=target/spring.log
1og4i.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d%p[%c]-%m%n
package yuzai.zk;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.junit.Test;
import javax.imageio.IIOException;
import java.io.IOException;
public class zkClient {
//注:"master:2181,slave1:2181,slave2:2181"的逗号左右不能有空格。
private String connectString = "master:2181,slave1:2181,slave2:2181";
private int sessionTimeout = 2000 ;
@Test
public void init() throws IOException {
ZooKeeper zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
}
});
}
}
package yuzai.zk;
import org.apache.zookeeper.*;
import org.junit.Before;
import org.junit.Test;
import javax.imageio.IIOException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
public class zkClient {
//注:"master:2181,slave1:2181,slave2:2181"的逗号左右不能有空格。
private String connectString = "192.168.187.198:2181,192.168.187.197:2181,192.168.187.196:2181";
private int sessionTimeout = 2000 ;
private static ZooKeeper zkClient ;
@Before
public void init() throws IOException {
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
}
});
}
@Test
public void creata() {
try {
String nodeCreated = zkClient.create("/adian", "xiaozahng".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
(1)先在集群上创建/servers节点
[zk: localhost:2181 (CONNECTED) 10]create /servers "servers "
(2)在Idea中创建包名: com.atguigu.zkcase1
(3)服务器端向Zookeeper注册代码
package yuzai.zk1;
import org.apache.zookeeper.*;
import java.io.IOException;
public class DistributeServer {
private String connectString = "192.168.187.198:2181,192.168.187.197:2181,192.168.187.196:2181";
private int sessionTimeout = 2000 ;
public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
DistributeServer server = new DistributeServer();
//1.获取zk连接
server.getConnect();
//2.注册服务器到zk集群
server.regist(args[0]);
//3.启动业务逻辑(睡觉觉)
server.business();
}
private void business() throws InterruptedException {
Thread.sleep(Long.MAX_VALUE);
}
private void regist(String hostname) throws InterruptedException, KeeperException {
String create = zk.create("/servers", hostname.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println(hostname+"is online");
}
ZooKeeper zk;
// 获取zk连接.方法
private void getConnect() throws IOException {
zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
}
});
}
}