Zookeeper数据模型
Zookeeper系统与标准的文件系统类似,节点可以拥有子节点,组成树形结构,节点都是有值的
Zookeeper节点类型
- 持久节点
客户端断开连接以后,数据依然存在 - 临时节点
客户端断开连接以后,数据不会存在 - 持久顺序节点
- 临时顺序节点
Zookeeper特性
-
会话
客户端与服务端的一次连接,本质是TCP长连接,通过会话可以进行心跳检测和数据传输 -
Watcher
事件器监听:对节点的值进行监听,当节点的值发生改变时,触发
Zookeeper实现分布式锁
原理:对于持久节点和临时节点,同一个znode节点下,节点的名称是唯一的
Zookeeper命令行命令
- ls /
查看 / 路径下所有节点 - create /zonde value
创建节点 - get /znode
获取节点的值 - create -e /zonde value
创建临时节点 - create -s /zonde value
创建顺序节点(相同命令可以重复执行,自动会加上顺序后缀) - delete /znode
删除节点 - set /znode value
修改znode的值为value - rmr /znode
递归删除节点与其下所有的子节点
Zookeeper启动命令(bin目录)
- ./zkServer.sh start 启动
- ./zkServer.sh status 查看状态
- ./zkServer.sh stop 停止
- ./zkCli.sh 客户端进入
Zookeeper客户端
- Zookeeper原生客户端
- ZkClient原生的封装
Zookeeper原生+springboot
- 引入pom依赖
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.8</version>
</dependency>
- 使用
package com.ciqu.zkclient;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
/*
任涛 -----专用
*/
public class ZkClientConnection {
//连接地址
private final static String CONNECTIONSTR="192.168.58.128:2181";
//超时时间
private final static int SESSIONTIMEOUT=5000;
//发令枪:阻塞作用
private static CountDownLatch countDownLatch=new CountDownLatch(1);
public static void main(String[] args) throws KeeperException, InterruptedException {
ZooKeeper zooKeeper= null;
try {
zooKeeper = new ZooKeeper(CONNECTIONSTR, SESSIONTIMEOUT, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
//监控连接状态:连接完成时,停止阻塞
if(watchedEvent.getState()==Event.KeeperState.SyncConnected){
countDownLatch.countDown();
System.out.println(watchedEvent.getState());
}
if(watchedEvent.getType()==Event.EventType.NodeDataChanged) {
//监控的节点数据发生了变化()
System.out.println("数据变更路径为"+watchedEvent.getPath());
}
}
});
countDownLatch.await();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(zooKeeper.getState());
//1:创建节点
//参数1:节点名称 参数2:节点值 参数3:ACL权限 参数4:节点类型
//String node2 = zooKeeper.create("/node2", "dubbo".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
//2:获取节点信息
//值的监控:条件:(1):watchedEvent.getType()==Event.EventType.NodeDataChanged
// (2):值变更前对其进行获取,进行监听watch=true
// (3):监听是一次性的,修改过一次后失效
Stat stat = new Stat();
byte[] data = zooKeeper.getData("/node2", true, stat);
String s = new String(data);
System.out.println("修改前"+s);
//3:修改节点
zooKeeper.setData("/node2", "dubbo3".getBytes(),-1);
zooKeeper.setData("/node2", "dubbo4".getBytes(),-1);
byte[] data1 = zooKeeper.getData("/node2", true, stat);
String s1 = new String(data1);
System.out.println("修改后"+s1);
//4:节点的删除
zooKeeper.delete("/node2",-1);
}
}
原生缺点
- 连接是异步的,连接成功以后才可进行下一步操作
- 对值的监听为一次性
ZkClient
import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import java.util.List;
import java.util.concurrent.TimeUnit;
/*
任涛 -----专用
*/
public class ZkClientConnection {
//连接地址
private final static String CONNECTIONSTR="192.168.58.128:2181";
//超时时间
private final static int SESSIONTIMEOUT=5000;
public static ZkClient getInstance(){
return new ZkClient(CONNECTIONSTR,SESSIONTIMEOUT);
}
public static void main(String[] args) throws InterruptedException {
//获得连接
ZkClient zkClient = getInstance();
//创建级联新增
zkClient.createPersistent("/node1/node1.1/node1.1.1/node1.1.1.1", true);
//值获取
List<String> children = zkClient.getChildren("/node1");
System.out.println(children.toString());
//节点删除
zkClient.deleteRecursive("/node1");
zkClient.createPersistent("/node2/node2.2/node2.2.2",true);
//节点数据监控
zkClient.subscribeDataChanges("/node2/node2.2", new IZkDataListener() {
@Override
public void handleDataChange(String s, Object o) throws Exception {
System.out.println("节点"+s+"修改后的值为--->"+o);
}
@Override
public void handleDataDeleted(String s) throws Exception {
}
});
//对节点的值进行修改
zkClient.writeData("/node2/node2.2","666");
TimeUnit.SECONDS.sleep(2);
zkClient.writeData("/node2/node2.2","777");
//节点下子节点状态监控
zkClient.subscribeChildChanges("/node2", new IZkChildListener() {
@Override
public void handleChildChange(String s, List<String> list) throws Exception {
System.out.println("节点"+s+"节点列表发生变化-->"+list);
}
});
zkClient.deleteRecursive("/node2");
//zkClient.delete("/node2/node2.2/node2.2.2");
TimeUnit.SECONDS.sleep(2);
//zkClient.delete("/node2/node2.2");
TimeUnit.SECONDS.sleep(2);
}
}