Zookeeper介绍,事件Watcher

1.什么是Zookeeper?
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。
ZooKeeper包含一个简单的原语集,提供Java和C的接口。
ZooKeeper代码版本中,提供了分布式独享锁、选举、队列的接口,代码在zookeeper-3.4.3\src\recipes。其中分布锁和队列有Java和C两个版本,选举只有Java版本。
1.2Zookeeper数据结构
1、层次化的目录结构,类似于树状结构。
如图:
Zookeeper介绍,事件Watcher_第1张图片
2、每个节点在zookeeper中叫做znode,并且其有一个唯一的路径标识 ,名称不可重复。

3、节点Znode可以包含数据和子节点(但是EPHEMERAL类型的节点不能有子节点)

1.3节点类型
1.3.1 PERSISTENT ,持久节点,持久存储在硬盘中,只有删除操作,即使关闭客户端也不影响数据。
1.3.2 PERSISTENT_SEQUENTIAL()
这类节点的基本特性和上面的节点类型是一致的。额外的特性是,在ZK中,每个父节点会为他的第一级子节点维护一份时序,会记录每个子节点创建的先后顺序。基于这个特性,在创建子节点的时候,可以设置这个属性,那么在创建节点过程中,ZK会自动为给定节点名加上一个数字后缀,作为新的节点名。这个数字后缀的范围是整型的最大值。
EPHEMERAL,临时节点
和持久节点不同的是,临时节点的生命周期和客户端会话绑定。也就是说,如果客户端会话失效,那么这个节点就会自动被清除掉。注意,这里提到的是会话失效,而非连接断开。另外,在临时节点下面不能创建子节点。

EPHEMERAL_SEQUENTIAL临时顺序节点
结合EPHEMERAL和SEQUENTIAL, 可以用来实现分布式锁
1.4Java操作Zookeeper
我创建的是SpringBoot项目,先在windows上搭建Zookepper,网上也很多教程,https://www.cnblogs.com/zlslch/p/8561791.html,安装Zookeeper可视化工具便于查看节点信息没我用的是ZooInspector。需要的评论联系我。
1.4.1 Maven添加依赖


			org.apache.zookeeper
			zookeeper
			3.4.6
```


1.4.2使用main函数创建持久节点
package com.cqr.demo.com.cqr.demo.test;

import org.apache.zookeeper.*;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;

/**

  • @ProjectName: car-zook

  • @Package: com.cqr.demo.com.cqr.demo.test

  • @ClassName: Test001

  • @Author: Cqr

  • @Description: ${description}

  • @Date: 2019/4/4 20:45

  • @Version: 1.0
    */
    public class Test001
    {

    //连接地址
    private static final String ADDRES = “127.0.0.1:2181”;
    //session 会话
    private static final int SESSION_OUTTIME = 2000;
    //信号量,阻塞程序执行,用户等待zookeeper连接成功,发送成功信号,因为Zookeeper走的是自己的线程,如果不使用信号量,就不会先连接ZooKeeper,而是先走main线程的代码,开始CountDownLatch的值为1,只有启动连接点后,countDownLatch.countDown()后,CountDownLatch变成0,这时阻塞通过,执行下面的代码。
    private static final CountDownLatch countDownLatch = new CountDownLatch(1);

    public static void main(String[] args) throws IOException,Exception {

     ZooKeeper zk =new ZooKeeper(ADDRES, SESSION_OUTTIME, new Watcher() {
         @Override
         public void process(WatchedEvent watchedEvent) {
             //获取事件状态
             Event.KeeperState keeperState=watchedEvent.getState();
             //获取事件类型
             Event.EventType eventType=watchedEvent.getType();
                 if(Event.KeeperState.SyncConnected ==keeperState){
                     if (Event.EventType.None == eventType) {
                         countDownLatch.countDown();
                         System.out.println("zk 启动连接...");
                     }
    
                 }
         }
     });
    
     // 进行阻塞
     countDownLatch.await();
     String result = zk.create("/cqy_test", "test".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,
             CreateMode.PERSISTENT);
     System.out.println(result);
     zk.close();
    

    }

}

执行之后在可视工具之中就会发现增加了一个节点cqy_test
如图
Zookeeper介绍,事件Watcher_第2张图片
1.5Zookeeper中的事件监听Watcher
在ZooKeeper中,接口类Watcher用于表示一个标准的事件处理器,其定义了事件通知相关的逻辑,包含KeeperState和EventType两个枚举类,分别代表了通知状态和事件类型,同时定义了事件的回调方法:process(WatchedEvent event)。
在 ZooKeeper 中,引入了 Watcher 机制来实现这种分布式的通知功能。ZooKeeper 允许客户端向服务端注册一个 Watcher 监听,当服务器的一些特定事件触发了这个 Watcher,那么就会向指定客户端发送一个事件通知来实现分布式的通知功能。
送上别人的图
Watcher通知状态与事件类型一览
Zookeeper介绍,事件Watcher_第3张图片
当我们写一个类实现Watcher时,会重写一个回调方法process(WatchedEvent event),当ZooKeeper向客户端发送一个Watcher事件通知时,客户端就会对相应的process方法进行回调,从而实现对事件的处理。
WatchedEvent包含每一事件的三种基本属性:通知状态、事件类型、节点路径。Zookeeper使用Watcher对象来封装服务器端事件,并传递给Watcher,从而方便回调方法process对服务器事件进行处理。
服务端在生成WatchedEvent事件之后,会调用getWrapper方法将自己包装成一个可序列化的WatcherEvent事件,以便通过网络传输到客户端。客户端在接收到服务端的这个事件对象后,首先会将WatcherEvent还原成一个WatchedEvent事件,并传递给process方法处理,回调方法process根据入参就能够解析出完整的服务端事件了。

package com.cqr.demo.com.cqr.demo.test;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.util.concurrent.CountDownLatch;

/**
 * @ProjectName: car-zook
 * @Package: com.cqr.demo.com.cqr.demo.test
 * @ClassName: ZKCliWatcher
 * @Author: XW
 * @Description: ${description}
 * @Date: 2019/4/8 16:58
 * @Version: 1.0
 */
public class ZKCliWatcher implements Watcher {
   
    // 会话超时时间
    private static final int SESSIONTIME = 2000;
    // 信号量,让zk在连接之前等待,连接成功后才能往下走.
    private static final CountDownLatch countDownLatch = new CountDownLatch(1);
    private ZooKeeper zk;

        /*
        * 创建连接
        * */
    public void createConnection(String address,int sessionTimeOut){
        try {
            zk = new ZooKeeper(address, sessionTimeOut,this);
            countDownLatch.await();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public boolean createPath(String path, String data) {
        try {
            this.exists(path, true);
            this.zk.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            System.out.println( "节点创建成功, Path:" + path + ",data:" + data);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public boolean updateNode(String path,String data) throws KeeperException, InterruptedException {
        exists(path, true);
        this.zk.setData(path, data.getBytes(), -1);
        return false;
    }

    /**
     * 判断指定节点是否存在
     *
     *
     *
     * */
    public Stat exists(String path, boolean watch) {
        try {
            return this.zk.exists(path, watch);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public void process(WatchedEvent watchedEvent) {
            //获取事件状态
        Event.KeeperState keeperState=watchedEvent.getState();
        //获取事件类型
        Event.EventType eventType=watchedEvent.getType();
        //zookeepe路径
        String path = watchedEvent.getPath();
        System.out.println("进入到 process()方法,keeperState:" + keeperState + ", eventType:" + eventType + ", path:" + path);
        if (Event.KeeperState.SyncConnected == keeperState) {
            if (Event.EventType.None == eventType) {
                // 如果建立建立成功,让后程序往下走
                System.out.println("zk 建立连接成功!");
                countDownLatch.countDown();
            } else if (Event.EventType.NodeCreated == eventType) {
                System.out.println( "事件通知,新增node节点" + path);
            } else if (Event.EventType.NodeDataChanged == eventType) {
                System.out.println( "事件通知,当前node节点" + path + "被修改....");
            }
            else if (Event.EventType.NodeDeleted == eventType) {
                System.out.println("事件通知,当前node节点" + path + "被删除....");
            }

        }
    }
    public static void main(String[] args) throws KeeperException, InterruptedException {
        ZKCliWatcher zkClientWatcher = new ZKCliWatcher();
        zkClientWatcher.createConnection("127.0.0.1:2181", SESSIONTIME);
//		boolean createResult = zkClientWatcher.createPath("/p15", "pa-644064");
        //zkClientWatcher.updateNode("/pa2","7894561");
        zkClientWatcher.createPath("/kl","lk");
    }

}

你可能感兴趣的:(Zookeeper,Watcher,Zookeeper,Watcher)