- zookeeper概念
Zookeeper是 Apache Hadoop项目下的一个子项目,是一个树形目录服务。Zookeeper翻译过来就是动物园管理员,他是用来管Hadoop(大象)、Hive(蜜蜂)、Pig(小猪)的管理员,简称zk,Zookeeper是一个分布式的、开源的应用程序的协调服务。所谓分布式协调主要是来解决分布式系统中多个进程之间的同步限制,防止出现脏读,例如我们常说的分布式锁。
zookeeper中的数据是存储在内存当中的,因此它的效率十分高效。它内部的存储方式十分类似于文件存储结构,采用了分层存储结构。但是它和文件存储结构的区别是,它的各个节点中是允许存储数据的,需要注意的是zk的每个节点存储数据不能超过1M。
zk拥有以下几个重要特性:
1)顺序一致性:来自客户端的相关指令会按照顺序执行,不会出现乱序的情况,客户端发送到服务的指令1->2->3->4,那个这些指令就会按照顺序执行;
2)原子性:更新只有成功和失败,没有中间状态;
3)可靠性:也可以称之为持久性,节点更新以后,在下次更新之前,它的数据不会发生变更;
4)准实时性:也可以称之为最终一致性,在zk集群中,一个客户端修改了其中的一个节点,一定时间以后,所有可用的服务对应的节点都会变成更新以后的值。
- zookeeper提供的主要功能包括:
- 配置管理:
在多个应用程序(或服务器)中,假如存在一些相同的配置信息,在对该配置信息进行修改时,我们需要一个一个进行修改,这样会大大增加维护的成本,不方便管理。这时如果使用一个专门放配置中心的组件,将相同的配置信息放在配置中心,需要的时候直接拉取,这样可以大大节约维护的成本, 而zookeeper即可实现配置中心的功能。
- 分布式锁:
在多个用户访问同一台主机上的应用程序数据时,我们可以通过加锁解决并发操作的问题,但是如果有多台主机相同的应用程序要访问同一数据时,这个时候我们在一台主机上加锁是不能解决另一台主机的并发问题的,换句话说自己的锁只对自己有效并不影响别的 ,这个时候就需要分布式锁解决这类问题,我个人理解分布式锁像是从所有主机中抽取出来的一把锁,或者是有一把总锁对所有主机都有效。zookeeper可以实现分布式锁的功能.
- 集群管理:
zookeeper作为注册中心,管理服务提供方的ip地址端口号url信息,并在服务消费方请求需要时发送给服务消费方.
- Zookeeper的安装
1.环境准备:zookeeper服务器是用Java创建的,运行在JVM之上。需要安装JDK7以上版本(最好JDK8或以上)
2.下载: 官网下载地址:Apache Downloads
4.上传并安装: 下载在本地之后可以把安装包上传到服务器或者虚拟机中,我使用的是服务器并远程shell连接,
上传到指定目录后使用tar -zxvf apache-zookeeper-3.8.1-bin.tar.gz命令解压安装包
- 配置: 进入conf配置目录
zoo_sample.cfg就是配置文件,但是此文件不能生效,需要名称为zoo.cfg的文件才能生效
改名复制一份配置文件
在zookeeper目录下新建一个目录zkdata(目录名随便取),用于存放zookeeper的持久化数据
Vim命令编辑配置文件zoo.cfg,更改数据目录,
wq命令保存
- 启动zookeeper:
启动成功
- Zookeeper内存模型
6.1:模型的特点:
每个子目录如/node1都被称作一个znode(节点)。这个znode是被它所在的路径唯一标识,znode可以有子节点目录,并且每个znode可以存储数据,znode是有版本的,每个znode中存储的数据可以有多个版本,也就是一个访问路径中可以存储多份数据,znode可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端
6.2:节点的分类:
1.持久节点(默认) 2.持久顺序节点 3.临时节点 4.临时顺序节点
create 节点path data
创建一个节点。并给节点绑定数据(默认是持久性节点)
create -s 节点path data
创建持久性顺序节点
create -e 节点path data
创建临时性节点
create -e -s 节点path data
创建临时顺序节点
(注意:临时节点不能含有任何子节点)
7.zookeeper配置文件详解
8.zookeeper客户端常用命令:
连接ZooKeeper服务端
./zkCli.sh -server ip:port 如果是本机连接可以不写 ip:port
断开连接 quit
CRUD
8.1.设置(修改)节点值
set 节点path value
8.2.查看命令帮助
help
8.3.删除单个节点
delete 节点path
8.4.显示指定目录下节点
ls 目录名
8.5.删除带有子节点的节点
deleteall 节点path
8.6.创建节点
create 节点path value
8.7.获取节点值
get 节点path
8.8.查看路径下节点信息及子节点
ls s 节点路径
8.9.查看节点状态
stat 节点path
节点监听机制watch
客户端可以监测znode节点的变化。Zonode节点的变化触发相应的事件,然后清除对该节点的监测。当监测一个znode节点时候,Zookeeper会发送通知给监测节点。在shell终端一个Watch事件是一个一次性的触发器,当被设置了Watch的数据或者目录发生了改变的时候,则服务器将这个改变发送给设置了Watch的客户端以便通知它们。
- ls -w 节点path 监听节点目录的变化
新建一个会话连接 对/app1的目录进行修改,增加一个子节点 create /app1/name
- get -w 节点path 监听节点数据的变化
- 修改节点信息
set /app1/***
四: Java客户端操作
导入zookeeper的依赖包和junit的测试包
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
1.连接zk server服务端:
@Before
public void before() {
/**
*参数1 --> zk server 服务ip地址:端口号
*参数2 --> 会话超时时间
*参数3 --> 连接超时时间
*参数4 --> 序列化方式
*/
zkClient = new ZkClient("ip:端口号", 60000 * 30, 60000, new SerializableSerializer());
}
private ZkClient zkClient;
@Test
public void test01(){
System.out.println(zkClient);
}
@After
public void after() {
zkClient.close();
}
6.2创建节点
@Test
public void test() {
//创建持久节点
zkClient.create("/app2", "xue", CreateMode.PERSISTENT);
//创建持久顺序节点
zkClient.create("/app3","yue", CreateMode.PERSISTENT_SEQUENTIAL);
//创建临时节点
zkClient.create("/app4","qing", CreateMode.EPHEMERAL);
//创建临时顺序节点
zkClient.create("/app5","haha",CreateMode.EPHEMERAL_SEQUENTIAL);
}
2.查看某个节点信息
@Test
public void test2(){
//查看某个节点数据,需要保证创建和获取的数据序列化方式相同,如果是在linux上创建的节点那么在Java上获取就会出现序列化不匹配的异常
Object o = zkClient.readData("/app2");
System.out.println(o);
//查看节点状态
Stat stat = new Stat();
System.out.println(o);
//查看节点创建时间
System.out.println(stat.getCtime());
//查看版本
System.out.println(stat.getCversion());
//查看id
System.out.println(stat.getCzxid());
}
3.修改节点信息
zkClient.writeData("/app2","xueyueqing");
4.查看当前节点所有子节点
@Test
public void test4(){
List<String> children = zkClient.getChildren("/");
for(String c : children ){
System.out.println(c);
}
}
6.监听
@Test
public void test5() throws IOException {
zkClient.subscribeDataChanges("/app1", new IZkDataListener() {
//当前节点数据变化时触发
@Override
public void handleDataChange(String dataPath, Object o) throws Exception {
System.out.println("当前节点路径"+dataPath);
System.out.println("当前节点信息"+o);
}
//当前节点删除时触发
@Override
public void handleDataDeleted(String dataPath) throws Exception {
System.out.println("当前节点路径"+dataPath);
}
});
//阻塞当前监听
System.in.read();
}
注意:在shell终端修改,Java是监听不了的,必须使用Java代码修改, Java代码进行监听是永久的,不是一次性的
@Test
public void test6() throws IOException {
//监听节点目录变化
zkClient.subscribeChildChanges("/app1", new IZkChildListener() {
@Override
public void handleChildChange(String s, List<String> list) throws Exception {
System.out.println("父节点名称:"+s);
System.out.println("发生变化后孩子节点名称:");
for(String child : list){
System.out.println(child);
}
}
});
//阻塞当前监听
System.in.read();
}