赞
踩
主要说的内容有以下几点:
1、在linux上安装zookeepr
2、基本的操作命令
3、java中zookeeper三种客户端基本编写
1、下载zookeeper安装包,下载地址
链接: https://pan.baidu.com/s/1r2co40V3PJGPZV4cOxC6rQ
密码:v4pa
2、安装目录,一般我会将所有的软件安装在/usr/local/soft中,使用 cd /usr/local/soft 该命令找到需要下载的目录,将zookeeper安装包上传到该目录下。
cd /usr/local/soft
3、使用该命令安装到当前目录下。
tar -zxvf apache-zookeeper-3.5.5-bin.tar.gz -C ./
4、进入zookeeper文件夹,找到conf文件夹,将里面的 zoo_sample.cfg文件复制一份,将名字改为zoo.cfg。该文件就是zookeeper的配置文件。
- //打开配置文件目录
- cd apache-zookeeper-3.5.5-bin/conf/
- //将配置文件复制一份,并改名为zoo.cfg
- cp zoo_sample.cfg zoo.cfg
5、修改完成后,进入到bin目录,启动zookeeper。
- //进入zookeeper的命令目录
- cd ..
- cd bin/
-
- //启动zookeeper
- ./zkServer.sh start
-
- //关闭zookeeper
- ./zkServer.sh stop
-
- //查看zookeeper状态
- ./zkServer.sh status
至此zookeeper安装完成。
zookeeper是一种类似于操作系统的文件系统数据结构,每个节点被称为znode,这个znode是可以存储数据的。
节点分为两大种,一种是持久化节点,一种是临时节点;
持久化节点又分为顺序持久化节点和持久化节点;
临时节点也分为顺序临时节点和临时节点。
当连接断掉后,所有的临时节点全部失效被删除;持久化节点则不会发生变化。
永久节点又分为顺序节点
1、安装好zookeeper后,可以使用命令进行查看是否启动成功。
- //查看zookeeper是否启动
- ps -ef | grep zookeeper
2、在bean目录下连接zookeeper
- //打开zookeeper连接命令
- ./zkCli.sh
创建节点
- //创建节点 -e(创建临时节点,不加则创建永久节点) /xaioabi(节点名) 测试创建节点 (节点存放的目录)
- create -e /xiaobai 测试创建节点
- create -e /xiaobai/test01 123456
需要注意的一点是,节点只能一级一级创建,不能直接创建多级节点
- //查看根目录节点
- ls /
- //查看xiaobai子节点
- ls /xiaobai
-
- //退出会话
- //关闭当前会话
- close
- //关闭当前连接
- quit
-
- //修改节点数据
- //修改test01节点数据
- set /xiaoabi/test01 13579
- //查看节点数据
- get /xiaobai/test01
-
- // 删除节点
- //删除节点(只能删除没有子节点的节点,如果有的话,要先删除子节点才能删除该节点)
- delete /xiaobai/test01
- //删除根目录下所有没有子节点的节点
- deleteall /
需要注意的是:
删除的节点有子节点,
如果子节点数据为空,使用deleteall可以进行删除;
如果子节点有数据,则会删除失败
java中使用zookeeper客户端有三种方式:
1、zookeeper:zookeeper提供的是原生java客户端
2、zkClient:在原生zookeeper基础上进行扩展的第三方java客户端
3、curator:Netflix公司在原生zookeeper基础上开源的java客户端
zookeeper原生客户端是官方提供的,此客户端所有的东西都需要自己手写,包括创建连接,手写增删改查语句。由于此客户端属于纯原生,所有东西都必须自己写,所以一般不会使用该客户端进行开发。
该客户端的弊端有一下几种:
1、会话的连接是异步的。如果创建连接,只有等监听连接成功后才可以进行操作;
2、Zookeeper的Watcher是一次性的,每次触发之后都需要重新进行注册;
3、Session超时之后没有重连机制;
4、异常处理繁琐,zookeeper提供了很多的异常。对于开发人员来说可能对这些异常都不知道如何处理;
5、只提供了简单的byte[]接口,没有提供对象级别的序列化;
6、开发的复杂性。创建节点前需要判断该节点是否存在;多级删除节点不支持,只能一级一级进行删除等等;
需要添加的依赖:
- <dependencies>
- <!--zookeeper的官方客户端jar包依赖-->
- <dependency>
- <groupId>org.apache.zookeeper</groupId>
- <artifactId>zookeeper</artifactId>
- <version>3.5.5</version>
- </dependency>
- </dependencies>
编写测试代码:
- package com.bpc.client;
- import org.apache.zookeeper.*;
- import org.apache.zookeeper.data.Stat;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.concurrent.CountDownLatch;
- /**
- * @author xiaobai
- */
- public class ZookeeperClientTest01 {
- private static final String ZK_ADDRESS = "127.0.0.1:2181";
- private ZooKeeper zooKeeper;
- private Integer sessionTimeout;
-
- /**
- * 删除节点
- */
- public void deletePath(String path) throws KeeperException, InterruptedException {
- //判断该节点下面是否有子节点,有子节点删除子节点
- List<String> childrenPathList = getChildrenPath(path);
- if (!childrenPathList.isEmpty()) {
- //删除子节点
- for (String childrenPath : childrenPathList) {
- //迭代删除子节点
- deletePath(path + "/" + childrenPath);
- }
- }
- zooKeeper.delete(path, -1);
- System.out.println("删除节点:" + path + "成功!");
- return;
- }
- /**
- * 获取所有子节点名称
- */
- public List<String> getChildrenPath(String path) throws KeeperException, InterruptedException {
- //判断该节点是否有子节点
- int numChildren = getNumChildren(path);
- if (0 == numChildren) {
- return new ArrayList<>();
- }
- return zooKeeper.getChildren(path, false);
- }
- /**
- * 修改节点内容
- */
- public void setContent(String path, String content) throws KeeperException, InterruptedException {
- //节点名称、修改内容,版本号(-1表示所有版本号都匹配)
- zooKeeper.setData(path, content.getBytes(), -1);
- }
- /**
- * 获取节点子节点数量
- */
- public int getNumChildren(String path) throws KeeperException, InterruptedException {
- //存放节点状态信息
- Stat stat = isExist(path);
- return stat == null ? 0 : stat.getNumChildren();
- }
- /**
- * 获取节点内容
- */
- public String getPath(String path) throws KeeperException, InterruptedException {
- //存放节点状态信息
- Stat stat = new Stat();
- byte[] data = zooKeeper.getData(path, false, stat);
- return new String(data);
- }
- /**
- * 检查节点是否存在
- */
- public Stat isExist(String path) throws KeeperException, InterruptedException {
- //节点名称、是否观察
- Stat stat = zooKeeper.exists(path, false);
- return stat;
- }
- /**
- * 创建节点
- */
- public String createNode(String path, String content) throws KeeperException, InterruptedException {
- //节点名称;节点存储内存数据;权限;节点状态(持久性节点)
- String pathNode = zooKeeper.create(path, content.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
- System.out.println("创建节点的结果:" + pathNode);
- return pathNode;
- }
- /**
- * 关闭会话连接
- */
- public void close() throws InterruptedException {
- zooKeeper.close();
- }
- /**
- * 获取连接
- */
- public ZooKeeper getConnect(int sessionTimeout) throws IOException, InterruptedException {
- //倒计数器,倒数1个
- CountDownLatch countDownLatch = new CountDownLatch(1);
- //创建zooKeeper对象
- //参数:连接地址和端口;会话超时时间(该连接保持时间);观察者对象(用来观察连接过程)
- ZooKeeper zooKeeper = new ZooKeeper(ZK_ADDRESS, sessionTimeout, (WatchedEvent event) -> {
- //判断状态是否是已连接
- if (Watcher.Event.KeeperState.SyncConnected.equals(event.getState())) {
- System.out.println("连接成功。。。。");
- //zookeeper连上了
- countDownLatch.countDown();
- }
- });
- //连接成功后返回zookeeper对象
- countDownLatch.await();
- return zooKeeper;
- }
- public ZookeeperClientTest01(Integer sessionTimeout) throws IOException, InterruptedException {
- this.sessionTimeout = sessionTimeout;
- this.zooKeeper = getConnect(sessionTimeout);
- }
- public ZooKeeper getZooKeeper() { return zooKeeper; }
- public void setZooKeeper(ZooKeeper zooKeeper) { this.zooKeeper = zooKeeper;}
- public Integer getSessionTimeout() { return sessionTimeout; }
- public void setSessionTimeout(Integer sessionTimeout) {this.sessionTimeout = sessionTimeout;}
- }
测试一下:
- public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
- //节点名称
- String path = "/test02";
- //创建对象并获取连接
- ZookeeperClientTest01 test01 = new ZookeeperClientTest01(5000);
-
- //检查节点是否存在
- Stat isExist = test01.isExist(path);
- if (null == isExist) {
- //创建节点
- test01.createNode(path, "创建节点内容");
- //创建子节点
- test01.createNode(path+"/test02","创建子节点001");
- }
- //获取节点
- String pathContent = test01.getPath(path);
- System.out.println("节点存放的内容:" + pathContent);
- //修改节点内容
- test01.setContent(path, "修改节点内容");
- //获取该节点下的所有子节点
- List<String> childrenPathList = test01.getChildrenPath(path);
- for (String childrenPath : childrenPathList) {
- System.out.println("子节点名称:" + childrenPath);
- }
- //删除节点
- test01.deletePath(path);
- //关闭会话
- test01.close();
-
- }
zkClient客户端是在原生zookeeper客户端上进行扩展的第三方开源客户端。该客户端在前几年被经常使用。
该客户端的优点:
1、提供了对象序列化的方式;
2、添加了session超时重试机制;
3、Wacther实现了反复注册;
4、对crud(增删改查)进行了封装处理;例如:提供了迭代删除接口等等;
该客户端的弊端:
1、几乎没有参考文档;
2、session超时重试机制比较难用
3、没有提供各种场景的实现
需要导入的依赖:
- <!-- zkclient 客户端-->
- <dependency>
- <groupId>com.101tec</groupId>
- <artifactId>zkclient</artifactId>
- <version>0.11</version>
- </dependency>
编写测试代码:
- package com.bpc.client;
- import org.I0Itec.zkclient.ZkClient;
- import java.util.List;
- /**
- * @author xiaobai
- */
- public class Test02 {
- public static void main(String[] args) {
- String ZK_ADDRESS = "127.0.0.1:2181";
- String path = "/test04";
- //创建连接
- ZkClient zkClient = new ZkClient(ZK_ADDRESS);
- //检查节点是否存在(节点名称)
- boolean isExist = zkClient.exists(path);
- //节点不存在则添加
- if (!isExist) {
- //创建节点(节点名称、节点内容)
- zkClient.createPersistent(path, "创建节点test004");
- //创建子节点(节点名称、节点内容)
- zkClient.createPersistent(path + "/znode01", "创建子节点znode01");
- }
- //获取节点数据(节点名称)
- String content = zkClient.readData(path);
- System.out.println("节点存储的数据:" + content);
- //修改节点内容(节点名称、节点内容)
- zkClient.writeData(path, "修改节点内容成功!");
- //获取所以子节点(节点名称)
- List<String> childrenList = zkClient.getChildren(path);
- for (String children : childrenList) {
- System.out.println("获取子节点名称:" + children);
- }
- //删除单节点删除(节点名称)
- boolean delete = zkClient.delete(path + "/znode01");
- System.out.println("删除单节点是否成功:" + delete);
- //递归删除多级节点(节点名称)
- boolean deleteAll = zkClient.deleteRecursive(path);
- System.out.println("删除多级节点是否成功:" + deleteAll);
- }
- }
curator客户端是目前官方推荐的,不管是从性能还是封装来说是目前比较好的框架。该框架是Netflix公司开发的开源框架,捐献给Apache后,成为Apache开源框架。相比于zookeeper客户端,进行了高度的封装和抽象,解决了非常底层的细节开发工作,包括超时重连机制、反复注册Watcher、NodeExistsException异常等等。并且提供了一套可读性和易用性的Fluent风格的API接口。
curator客户端的优点:
1、提供了一套Fluent风格的API接口,大大提高了可读性和易用性;
2、解决Watcher注册一次就会失效的问题,实现了Wacther反复注册;
3、提供了不同场景的抽象封装,例如:共享锁服务、Master选举机制和分布式计算器等场景;
4、更加倾向于开发人员,例如:链式调用风格、分布式锁、zookeeper工具类等等;
5、该框架为我们封装了很多逻辑和方法,使得框架的容错性大大提供。使得我们开发人员更专注于业务。
需要导入的依赖:
- <!-- curator-framework -->
- <dependency>
- <groupId>org.apache.curator</groupId>
- <artifactId>curator-framework</artifactId>
- <version>4.2.0</version>
- </dependency>
- <!-- curator-recipes -->
- <dependency>
- <groupId>org.apache.curator</groupId>
- <artifactId>curator-recipes</artifactId>
- <version>4.2.0</version>
- </dependency>
编写测试代码:
- public static void main(String[] args) throws Exception {
- String path = "/test05";
- CuratorTest03 curator = new CuratorTest03();
-
- //检查节点是否存在
- Stat stat = curator.client.checkExists().forPath(path);
- if (null == stat) {
- //创建节点
- curator.client.create()
- .creatingParentsIfNeeded()
- .withMode(CreateMode.PERSISTENT)
- .forPath(path, "创建节点test05".getBytes());
- //创建子节点
- curator.client.create()
- .creatingParentsIfNeeded()
- .withMode(CreateMode.PERSISTENT)
- .forPath(path + "/test01", "创建子节点test01".getBytes());
- curator.client.create()
- .creatingParentsIfNeeded()
- .withMode(CreateMode.PERSISTENT)
- .forPath(path + "/test02", "创建子节点test02".getBytes());
- }
- //修改节点数据
- curator.client.setData().forPath(path, "修改主节点数据内容".getBytes());
- //获取节点数据
- String node = new String(curator.client.getData().forPath(path));
- String test01Node = new String(curator.client.getData().forPath(path + "/test01"));
- System.out.println("主节点数据:" + node);
- System.out.println("子节点Test01数据:" + test01Node);
- //获取所有子节点
- List<String> childrenList = curator.client.getChildren().forPath(path);
- for (String children : childrenList) {
- System.out.println("子节点名称:" + children);
- }
- //单个节点删除
- curator.client.delete().forPath(path + "/test02");
- //迭代删除节点
- curator.client.delete().deletingChildrenIfNeeded().forPath(path);
- //查看节点是否存在
- Stat stat1 = curator.client.checkExists().forPath(path);
- if (null == stat1) {
- System.out.println(path + "节点不存在");
- } else {
- System.out.println(path + "该节点存在");
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。