ZooKeeper

  1. ZooKeeper简介
  2. ZooKeeper安装
  3. ZooKeeper使用
  4. ZooKeeper监听机制
  5. ZooKeeper分布式锁
  6. ZooKeeper集群介绍
ZooKeeper简介

prothemus监控zookeeper zookeeper监听机制原理_java

ZooKeeper安装

ZooKeeper是一个绿色软件,Windows版本的直接解压就可以,进入bin目录可以启动服务端和客户端。

ZooKeeper使用

使用之前先了解ZooKeeper的数据模型:

prothemus监控zookeeper zookeeper监听机制原理_System_02


JavaAPI的相关操作:

使用Java操作需要用到一个客户端Curator:

Curator 介绍

  • Curator 是 Apache ZooKeeper 的Java客户端库。
  • 常见的ZooKeeper Java API :
    原生Java API
    ZkClient
    Curator
  • Curator 项目的目标是简化 ZooKeeper 客户端的使用。
  • Curator 最初是 Netfix 研发的,后来捐献了 Apache 基金会,目前是 Apache 的顶级项目。
  • 官网:http://curator.apache.org

Curator关于节点的操作:

public class ConnectionTest {

    private CuratorFramework client = null;
    @Before
    public void testConnection() {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
        client =
                CuratorFrameworkFactory.builder()
                        .connectString("localhost:2181")
                        .sessionTimeoutMs(60 * 1000)
                        .connectionTimeoutMs(15 * 1000)
                        .namespace("ys")
                        .retryPolicy(retryPolicy).build();

        client.start();
    }

    /**
     * 创建节点:create 持久 临时 顺序 数据
     * 1. 基本创建 :create().forPath("")
     * 2. 创建节点 带有数据:create().forPath("",data)
     * 3. 设置节点的类型:create().withMode().forPath("",data)
     * 4. 创建多级节点  /app1/p1 :create().creatingParentsIfNeeded().forPath("",data)
     */

    @Test
    public void testCreate() throws Exception {
//        创建节点
        client.create().forPath("/app1");

    }

    @Test
    public void testCreateData() throws Exception {
//        创建节点
        client.create().forPath("/app2", "ys".getBytes());

    }

    @Test
    public void testCreate2() throws Exception {
//        创建带有类型的节点
        client.create().withMode(CreateMode.PERSISTENT).forPath("/app3", "persistent".getBytes());

    }

    @Test
    public void testCreate3() throws Exception {
//        创建带有子节点的多级节点
        client.create().creatingParentsIfNeeded().forPath("/app4/a1/b2");

    }

    /**
     * 查询节点:
     * 1. 查询数据:get: getData().forPath()
     * 2. 查询子节点: ls: getChildren().forPath()
     * 3. 查询节点状态信息:ls -s:getData().storingStatIn(状态对象).forPath()
     */
    @Test
    public void testGet1() throws Exception {
//        查询数据
        byte[] bytes = client.getData().forPath("/app2");
        System.out.println(new String(bytes));
    }


    @Test
    public void testGet2() throws Exception {
//        查询子节点
        List<String> strings = client.getChildren().forPath("/app3");

        System.out.println(strings);
    }

    @Test
    public void testCreate5() throws Exception {
//        查询节点状态信息
        Stat stat = new Stat();

        byte[] bytes = client.getData().storingStatIn(stat).forPath("/app3");

        System.out.println(new String(bytes));

    }

    /**
     * 修改数据
     * 1. 基本修改数据:setData().forPath()
     * 2. 根据版本修改: setData().withVersion().forPath()
     * * version 是通过查询出来的。目的就是为了让其他客户端或者线程不干扰我。
     *
     * @throws Exception
     */
    @Test
    public void testUpdate() throws Exception {
        Stat stat = new Stat();
        client.getData().storingStatIn(stat).forPath("/app2");
        System.out.println(stat.getVersion());
        int version = stat.getVersion();
        client.setData().withVersion(version).forPath("/app2","after".getBytes());

        client.getData().storingStatIn(stat).forPath("/app2");
        System.out.println(stat.getVersion());
    }

    /**
     * 删除节点: delete deleteall
     * 1. 删除单个节点:delete().forPath("/app1");
     * 2. 删除带有子节点的节点:delete().deletingChildrenIfNeeded().forPath("/app1");
     * 3. 必须成功的删除:为了防止网络抖动。本质就是重试。  client.delete().guaranteed().forPath("/app2");
     * 4. 回调:inBackground
     * @throws Exception
     */

    @Test
    public void testDelete1() throws Exception {
        client.delete().forPath("/app2");
    }

    @Test
    public void testDelete2() throws Exception {
        client.delete().deletingChildrenIfNeeded().forPath("/app3");
    }

    @Test
    public void testDelete3() throws Exception {
        client.delete().guaranteed().forPath("/app1");
    }




    @Test
    public void testDelete4() throws Exception {
        client.delete().inBackground((CuratorFramework client, CuratorEvent event)-> System.out.println(event)).forPath("/app1");
    }


    @After
    public void testClose() {
        client.close();
    }

}
ZooKeeper监听机制

prothemus监控zookeeper zookeeper监听机制原理_Test_03

使用JavaAPI实现监听:

public class ListenerTest {

    private CuratorFramework client = null;
    @Before
    public void testConnection() {

        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
        client = CuratorFrameworkFactory.builder().connectString("localhost:2181")
                .namespace("ys")
                .retryPolicy(retryPolicy).build();

        client.start();

    }

    @Test
    public void testListener1() throws Exception {
//        NodeCache:只监听特定节点的修改、删除、创建事件

        NodeCache nodeCache = new NodeCache(client, "/node1");
        nodeCache.getListenable().addListener(new NodeCacheListener() {
            @Override
            public void nodeChanged() throws Exception {
                System.out.println("节点变化了");

                byte[] data = nodeCache.getCurrentData().getData();
                System.out.println(new String(data));
            }
        });

        nodeCache.start(true);
        while (true) {

        }
    }


    @Test
    public void testListener2() throws Exception {
        //1.创建监听对象
        PathChildrenCache pathChildrenCache = new PathChildrenCache(client,"/node2",true);

        //2. 绑定监听器
        pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
            @Override
            public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
                System.out.println("子节点变化了~");
                System.out.println(event);
                //监听子节点的数据变更,并且拿到变更后的数据
                //1.获取类型
                PathChildrenCacheEvent.Type type = event.getType();
                //2.判断类型是否是update
                if(type.equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){
                    System.out.println("数据变了!!!");
                    byte[] data = event.getData().getData();
                    System.out.println(new String(data));

                }
            }
        });
        //3. 开启
        pathChildrenCache.start();

        while (true){

        }
    }

    @Test
    public void testListener3() throws Exception {
        //1. 创建监听器
        TreeCache treeCache = new TreeCache(client,"/node3");

        //2. 注册监听
        treeCache.getListenable().addListener(new TreeCacheListener() {
            @Override
            public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {
                System.out.println("节点变化了");
                System.out.println(event);
            }
        });

        //3. 开启
        treeCache.start();

        while (true){

        }
    }



    @After
    public void testClose() {

        client.close();
    }
ZooKeeper分布式锁

prothemus监控zookeeper zookeeper监听机制原理_zookeeper_04

ZooKeeper分布式锁原理:
• 核心思想:当客户端要获取锁,则创建节点,使用完锁,则删除该节点。

  1. 客户端获取锁时,在lock节点下创建临时顺序节点。
  2. 然后获取lock下面的所有子节点,客户端获取到所有的子节点之后,如果发现自己创建的子节点序号最小,那么就认为该客户端获取到了锁。使用完锁后,将该节点删除。
  3. 如果发现自己创建的节点并非lock所有子节点中最小的,说明自己还没有获取到锁,此时客户端需要找到比自己小的那个节点,同时对其注册事件监听器,监听删除事件。
  4. 如果发现比自己小的那个节点被删除,则客户端的Watcher会收到相应通知,此时再次判断自己创建的节点是否是lock子节点中序号最小的,如果是则获取到了锁,如果不是则重复以上步骤继续获取到比自己小的一个节点
    并注册监听。

    Curator实现分布式锁API,在Curator中有五种锁方案:
    • InterProcessSemaphoreMutex:分布式排它锁(非可重入锁)
    • InterProcessMutex:分布式可重入排它锁
    • InterProcessReadWriteLock:分布式读写锁
    • InterProcessMultiLock:将多个锁作为单个实体管理的容器
    • InterProcessSemaphoreV2:共享信号量
ZooKeeper集群介绍

prothemus监控zookeeper zookeeper监听机制原理_分布式_05


prothemus监控zookeeper zookeeper监听机制原理_java_06

以上就是本次介绍的全部内容了