数据存储
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 }