数据存储

DataTree ConcurrentHashMap

zoo.cfg dataDir 默认存储在/tmp/zookeeper

事务日志 一般挂载在单独的磁盘

快照日志

运行时日志 bin/zookeeper.out

基于Java API Zookeeper的使用

引入Jar包

1 <dependency>
2     <groupId>org.apache.zookeeper</groupId>
3     <artifactId>zookeeper</artifactId>
4     <version>3.4.13</version>
5 </dependency>

基于原生API的增删改查操作

1 package com.binwang.zookeeper;
 2 import org.apache.zookeeper.*;
 3 import org.apache.zookeeper.data.Stat;
 4 import java.io.IOException;
 5 import java.util.concurrent.CountDownLatch;
 6 public class ConnectionDemo {
 7     public static void main(String args[]) {
 8         try {
 9             final CountDownLatch countDownLatch = new CountDownLatch(1);
10             ZooKeeper zooKeeper = new ZooKeeper("192.168.15.134:2181,192.168.15.139:2181,192.168.15.140:2181", 4000, new Watcher() {
11                 @Override
12                 public void process(WatchedEvent watchedEvent) {
13                     if (Event.KeeperState.SyncConnected == watchedEvent.getState()) {
14                         //收到服务端的响应事件,连接成功
15                         countDownLatch.countDown();
16                     }
17                 }
18             });
19             countDownLatch.await();
20             //连接状态 CONNECTED
21             System.out.println(zooKeeper.getState());
22             //添加节点
23             zooKeeper.create("/zk-persis-order", "http://www.baidu.com".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
24             Thread.sleep(2000);
25             Stat stat = new Stat();
26             //得到当前节点的值
27             byte[] bytes = zooKeeper.getData("/zk-persis-order", null, stat);
28             System.out.println(new String(bytes));
29             //修改节点值
30             zooKeeper.setData("/zk-persis-order", "http://www.qq.com".getBytes(), stat.getVersion());
31             byte[] bytes1 = zooKeeper.getData("/zk-persis-order", null, stat);
32             System.out.println(new String(bytes1));
33             zooKeeper.delete("/zk-persis-order", stat.getVersion());
34 //            Thread.sleep(2000);
35 //            //连接状态 CONNECTED
36 //            System.out.println(zooKeeper.getState());
37             zooKeeper.close();
38             System.in.read();
39         } catch (IOException | InterruptedException | KeeperException e) {
40             e.printStackTrace();
41         }
42     }
43 }

基于原生API的Watcher使用

package com.binwang.zookeeper;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
public class WatcherDemo {
    public static void main(String args[]) {
        try {
            final CountDownLatch countDownLatch = new CountDownLatch(1);
            ZooKeeper zooKeeper = new ZooKeeper("192.168.15.134:2181,192.168.15.139:2181,192.168.15.140:2181", 4000, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    System.out.println("默认事件:"+watchedEvent.getType());
                    if (Event.KeeperState.SyncConnected == watchedEvent.getState()) {
                        //收到服务端的响应事件,连接成功
                        countDownLatch.countDown();
                    }
                }
            });
            countDownLatch.await();
            zooKeeper.create("/zk-persis-order", "http://www.baidu.com".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

            //exists getdata getchildren
            //zooKeeper.exists("/zk-persis-order",true);
            //通过exists绑定事件
            Stat stat = zooKeeper.exists("/zk-persis-order", new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    System.out.println(event.getType() + "->" + event.getPath());
                    //再一次去绑定事件
                    try {
                        zooKeeper.exists("/zk-persis-order", true);
                    } catch (KeeperException e) {
                        e.printStackTrace();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            //通过修改的事务类型来操作触发监听事件
            stat = zooKeeper.setData("/zk-persis-order", "http://www.qq.com".getBytes(), stat.getVersion());
            Thread.sleep(1000);
            zooKeeper.delete("/zk-persis-order", stat.getVersion());
            System.in.read();
        } catch (IOException | InterruptedException | KeeperException e) {
            e.printStackTrace();
        }
    }
}

Watcher 机制

基于Zookeeeper 上创建的节点,可以对这些节点绑定监听事件,比如监听节点数据变更、节点删除、子节点状态变更等事件,通过这个事件机制,可以基于zookeeper 实现分布式锁、集群管理等

Watcher 特性:当数据发生变化的时候,zookeeper 会产生一个watcher 事件,并且会发送到客户端。但是客户端只会收到一次通知。如果后续这个节点再次发生变化,那么之前设置watcher的客户端不会再收到消息。(watcher 是一次性的操作)可以通过循环监听达到永久监听效果

如何注册事件机制

通过这三个操作来绑定事件:getData、Exists、getChildren

如何触发事件

事务类型的操作,都会触发监听事件。create/setData/delete

Watcher 事件类型

1 None(-1),   //客户端连接状态发生变化的时候,会收到none的事件
2 NodeCreated(1),  //创建节点的事件
3 NodeDeleted(2),  //删除节点事件
4 NodeDataChanged(3), //节点数据发生变更
5 NodeChildrenChanged(4); //子节点被创建、被删除、会发生事件触发

什么样的操作会产生什么类型的事件

 

/zk-persis-order(监听事件)

/zk-persis-order/child(监听事件)

create(/zk-persis-order)

NodeCreated(getData/exists)


delete(/zk-persis-order)

NodeDeleted(getData/exists)


setData(/zk-persis-order)

NodeDataChanged(getData/exists)


create(/zk-persis-order/child)

NodeChildrenChanged(getChild)

NodeCreated

delete(/zk-persis-order/child)

NodeChildrenChanged(getChild)

NodeDeleted

setData(/zk-persis-order/child)

 

NodeDataChanged

Curator 客户端的使用

引入JAR包

1 <dependency>
 2        <groupId>org.apache.curator</groupId>
 3        <artifactId>curator-framework</artifactId>
 4        <version>4.0.1</version>
 5 </dependency>
 6 <dependency>
 7       <groupId>org.apache.curator</groupId>
 8       <artifactId>curator-recipes</artifactId>
 9       <version>4.0.1</version>
10 </dependency>

CuratorFramework的使用

1 package com.binwang.zookeeper;
 2 import org.apache.curator.framework.CuratorFramework;
 3 import org.apache.curator.framework.CuratorFrameworkFactory;
 4 import org.apache.curator.retry.ExponentialBackoffRetry;
 5 import org.apache.zookeeper.CreateMode;
 6 import org.apache.zookeeper.data.Stat;
 7 
 8 public class CuratorDemo {
 9     public static void main(String args[]) {
10         CuratorFramework curatorFramework = CuratorFrameworkFactory.builder()
11                 .connectString("192.168.15.134:2181,192.168.15.139:2181,192.168.15.140:2181")
12                 //会话超时时间
13                 .sessionTimeoutMs(4000)
14                 //重试策略四种方式 递减衰减重试
15                 .retryPolicy(new ExponentialBackoffRetry(1000, 3))
16                 //指定一个命名空间
17                 .namespace("curator")
18                 .build();
19         curatorFramework.start();
20         try {
21             //结果:/curator/order/node1
22             //原生API中,必须逐层创建,也就是父节点必须存在,子节点才能创建
23             curatorFramework.create().creatingParentsIfNeeded()
24                     .withMode(CreateMode.PERSISTENT)
25                     .forPath("/order/node1","1".getBytes());
26             //修改
27             Stat stat = new Stat();
28             curatorFramework.getData().storingStatIn(stat).forPath("/order/node1");
29 curatorFramework.setData().withVersion(stat.getVersion()).forPath("/order/node1","http://wwww.baidu.com".getBytes());
30             //删除
31             curatorFramework.delete().deletingChildrenIfNeeded().forPath("/order/node1");
32             curatorFramework.close();
33         } catch (Exception e) {
34             e.printStackTrace();
35         
36     }
37 }

使用Curator 实现Watcher

1 package com.binwang.zookeeper;
  2 import org.apache.curator.framework.CuratorFramework;
  3 import org.apache.curator.framework.CuratorFrameworkFactory;
  4 import org.apache.curator.framework.recipes.cache.*;
  5 import org.apache.curator.retry.ExponentialBackoffRetry;
  6 public class CuratorWatcherDemo {
  7     public static void main(String args[]) throws Exception {
  8         CuratorFramework curatorFramework = CuratorFrameworkFactory.builder()
  9                 .connectString("192.168.15.134:2181,192.168.15.139:2181,192.168.15.140:2181")
 10                 .sessionTimeoutMs(4000)
 11                 .retryPolicy(new ExponentialBackoffRetry(1000, 3))
 12                 .namespace("curator")
 13                 .build();
 14         curatorFramework.start();
 15         //NodeCache 监听一个节点的更新和创建事件
 16         //测试用例:zookeeper客户端执行  set /curator/order abc  IDE客户端响应Recive event:/order
 17         //create /curator/order 123 响应Recive event:/order
 18         //addListenerWithNodeCache(curatorFramework,"/order");
 19         
 20 
 21         //PathChildCache 监听一个节点下子节点的创建、删除、更新
 22         //测试用例:zookeeper客户端执行  create /curator/order/node1 123 IDE客户端响应Recive event:CHILD_ADDED
 23         // set /curator/order/node1 1122   响应Recive event:CHILD_UPDATED
 24         //delete /curator/order/node1   响应 Recive event:CHILD_REMOVED
 25         //addListenerWithPathChildCache(curatorFramework,"/order");
 26         
 27         //综合节点的监听事件
 28         //set /curator/order test NODE_UPDATED->NODE_UPDATED
 29         //create /curator/order/node2 12345  NODE_ADDED->NODE_ADDED
 30         //delete /curator/order/node2  NODE_REMOVED->NODE_REMOVED
 31         addListenerWithTreeCache(curatorFramework, "/order");
 32         //进程阻塞
 33         System.in.read();
 34     }
 35 
 36     /***
 37      * PathChildrenCache 监听一个节点下子节点的创建、删除、更新
 38      * NodeCache 监听一个节点的更新和创建事件
 39      * TreeCache  综合PathChildCache 和NodeCache 的特性
 40      */
 41     public static void addListenerWithNodeCache(CuratorFramework curatorFramework, String path) throws Exception {
 42         //第一个参数就是传入创建的Curator客户端即可
 43         //第二个参数就是监听节点的路径
 44         //第三个dataIsCompressed参数表示是否对数据进行压缩。
 45         NodeCache nodeCache = new NodeCache(curatorFramework, path, false);
 46 
 47         NodeCacheListener nodeCacheListener = new NodeCacheListener() {
 48             @Override
 49             public void nodeChanged() throws Exception {
 50                 System.out.println("Recive event:" + nodeCache.getCurrentData().getPath());
 51             }
 52         };
 53         nodeCache.getListenable().addListener(nodeCacheListener);
 54 
 55         nodeCache.start();
 56     }
 57 
 58     /***
 59      * PathChildCache 监听一个节点下子节点的创建、删除、更新
 60      * NodeCache 监听一个节点的更新和创建事件
 61      * TreeCache  综合PathChildCache 和NodeCache 的特性
 62      */
 63     public static void addListenerWithPathChildCache(CuratorFramework curatorFramework, String path) throws Exception {
 64         //第一个参数就是传入创建的Curator客户端即可
 65         //第二个参数就是监听节点的路径
 66         //第三个dataIsCompressed参数表示是否对数据进行压缩。
 67         PathChildrenCache pathChildrenCache = new PathChildrenCache(curatorFramework, path, false);
 68 
 69         PathChildrenCacheListener pathChildrenCacheListener = new PathChildrenCacheListener() {
 70 
 71             @Override
 72             public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
 73                 System.out.println("Recive event:" + pathChildrenCacheEvent.getType());
 74             }
 75         };
 76         pathChildrenCache.getListenable().addListener(pathChildrenCacheListener);
 77 
 78         pathChildrenCache.start();
 79     }
 80 
 81     /***
 82      * PathChildCache 监听一个节点下子节点的创建、删除、更新
 83      * NodeCache 监听一个节点的更新和创建事件
 84      * TreeCache  综合PathChildCache 和NodeCache 的特性
 85      */
 86     public static void addListenerWithTreeCache(CuratorFramework curatorFramework, String path) throws Exception {
 87         //第一个参数就是传入创建的Curator客户端即可
 88         //第二个参数就是监听节点的路径
 89         //第三个dataIsCompressed参数表示是否对数据进行压缩。
 90         TreeCache treeCache = new TreeCache(curatorFramework, path);
 91         TreeCacheListener treeCacheListener = new TreeCacheListener() {
 92             @Override
 93             public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
 94                 System.out.println(treeCacheEvent.getType() + "->" + treeCacheEvent.getType());
 95             }
 96         };
 97         treeCache.getListenable().addListener(treeCacheListener);
 98         treeCache.start();
 99     }
100 }