ZooKeeper 就是动物园管理员,他是用来管 hadoop(大象)、Hive(蜜蜂)等的管理员。
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Hadoop、Hbase、kafka、dubbo等重要组件。
ZooKeeper是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。ZooKeeper包含一个简单的原语集,提供Java和C的接口。
简单来说,ZooKeeper有两个功能:管理数据+监听数据
管理数据就得有一个结构对数据进行存储,然后才能进行数据的增删改查。
zookeeper 中的数据是按照“树”结构进行存储的,根目录下有多个子目录,子目录下还可以创建/删除子目录;每个子目录项如 NameService 都被称作为 znode(目录节点),和文件系统一样,能够自由的增加、删除znode,唯一的不同在于znode是可以存储数据的。
节点类型:
(1)PERSISTENT 持久化节点: 所谓持久节点,是指在节点创建后,就一直存在,直到 有删除操作来主动清除这个节点。否则不会因为创建该节点的客户端会话失效而消失。
(2)PERSISTENT_SEQUENTIAL 持久顺序节点:这类节点的基本特性和上面的节点类 型是一致的。额外的特性是,在 ZK 中,每个父节点会为他的第一级子节点维护一份时序, 会记录每个子节点创建的先后顺序。基于这个特性,在创建子节点的时候,可以设置这个属 性,那么在创建节点过程中,ZK 会自动为给定节点名加上一个数字后缀,作为新的节点名。 这个数字后缀的范围是整型的最大值。 在创建节点的时候只需要传入节点 “/test_”,这样 之后,zookeeper 自动会给”test_”后面补充数字。
(3)EPHEMERAL 临时节点:和持久节点不同的是,临时节点的生命周期和客户端会话绑定。也就是说,如果客户端会话失效,那么这个节点就会自动被清除掉。注意,这里提到的是会话失效,而非连接断开。另外,在临时节点下面不能创建子节点。 这里还要注意一件事,就是当你客户端会话失效后,所产生的节点也不是一下子就消失了,也要过一段时间,大概是 10 秒以内,可以试一下,本机操作生成节点,在服务器端用 命令来查看当前的节点数目,你会发现客户端已经 stop,但是产生的节点还在。
(4) EPHEMERAL_SEQUENTIAL 临时自动编号节点:此节点是属于临时节点,不过带 有顺序,客户端会话结束节点就消失。
客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、被删除、子目录节点增加删除)时,zookeeper会通知客户端。
不注册监听
package zookeeper.demo;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.junit.Before;
import org.junit.Test;
public class ClientDemo {
ZooKeeper zk = null;
@Before
// 新建一个客户端对象
public void init() throws IOException{
// 参数1:连接的zookeeper地址(最好写多台),参数2:会话超时时间
// 参数3:接口实现类;当监听发生时,zookeeper会告知客户端,此时客户端需要做逻辑处理,这里传的参数就是接口的实现类,里面具体写实现的逻辑
zk = new ZooKeeper("hadoop100:2181,hadoop101:2181,hadoop102:2181", 2000, null);
}
@Test
// 创建节点
public void testCreate() throws KeeperException, InterruptedException{
// 参数1:节点路径 参数2:数据 参数3:访问权限 参数4:节点类型(持久、短暂、有序或 组合类型)
String create = zk.create("/eclipse", "hello".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println(create);
zk.close();
}
@Test
// 更新节点数据
public void testUpdate() throws UnsupportedEncodingException, KeeperException, InterruptedException{
// 1:节点路径, 2:数据, 3:要修改的数据版本,-1代表修改任意版本为最新数据
zk.setData("/eclipse", "我爱你".getBytes("UTF-8"), -1);
zk.close();
}
@Test
// 查看节点的数据内容
public void testGet() throws Exception{
// 1:节点路径, 2:是否需要监听, 3:获取的数据的版本,null表示获取最新版本
byte[] data = zk.getData("/eclipse", false, null);
System.out.println(new String(data,"utf-8"));
zk.close();
}
@Test
// 查看该节点下有什么子节点
public void testListChildren() throws Exception, InterruptedException{
List<String> children = zk.getChildren("/eclipse", false);
for (String child : children) {
System.out.println(child);
}
zk.close();
}
@Test
// 删除节点
public void testRm() throws InterruptedException, KeeperException{
zk.delete("/eclipse", -1);
zk.close();
}
}
注册监听
package zookeeper.demo;
import java.io.IOException;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooKeeper;
import org.junit.Before;
import org.junit.Test;
public class WatcherDemo {
ZooKeeper zk = null;
@Before
public void init() throws IOException {
// 参数1:连接的zookeeper地址(最好写多台),参数2:会话超时时间
// 参数3:接口实现类;当监听发生时,zookeeper会告知客户端,此时客户端需要做逻辑处理,这里传的参数就是接口的实现类,里面具体写实现的逻辑
zk = new ZooKeeper("hadoop100:2181,hadoop101:2181,hadoop102:2181",
2000, new Watcher() {
@Override
public void process(WatchedEvent event) {
// TODO Auto-generated method stub
if (event.getState() == KeeperState.SyncConnected && event.getType() == EventType.NodeDataChanged) {
System.out.println(event.getPath());
System.out.println(event.getType());
System.out.println("节点数据的监听事件发生了...");
// 反复监听
try {
zk.getData("/eclipse", true, null);
} catch (KeeperException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
}
@Test
public void testGet() throws Exception {
// 1:节点路径, 2:是否需要监听, 3:获取的数据的版本,null表示获取最新版本
byte[] data = zk.getData("/eclipse", true, null);
System.out.println(new String(data, "utf-8"));
Thread.sleep(Long.MAX_VALUE);
}
}
参考:https://my.oschina.net/u/3796575/blog/1845035