一.Zookeeper命令行操作
1. 客户端连接:运行 zkCli.sh –server <ip>进入命令行工具
2.查看znode路径:ls /mygirls
3. 获取znode数据:get /mygirls
4. 监听znode事件:
ls /mygirls watch ## 就对一个节点的子节点变化事件注册了监听
get /mygirls watch ## 就对一个节点的数据内容变化事件注册了监听
注意: 监听器只生效一次
监听器的工作机制,其实是在客户端会专门创建一个监听线程,在本机的一个端口上等待zk集群发送过来事件
二.Zookeeper核心工作机制
1. zookeeper特性
1/Zookeeper:一个leader,多个follower组成的集群
2/全局数据一致:每个server保存一份相同的数据副本,client无论连接到哪个server,数据都是一致的
3/分布式读写,更新请求转发,由leader实施
4/更新请求顺序进行,来自同一个client的更新请求按其发送顺序依次执行
5/数据更新原子性,一次数据更新要么成功(半数以上节点成功),要么失败
6/实时性,在一定时间范围内,client能读到最新数据
2.zookeeper数据结构
1/层次化的目录结构,命名符合常规文件系统规范(见下图)
2/每个节点在zookeeper中叫做znode,并且其有一个唯一的路径标识
3/节点Znode可以包含数据(只能存储很小量的数据,<1M;最好是1k字节以内)和子节点(但是EPHEMERAL类型的节点不能有子节点)
3. 节点类型
1/Znode有两种类型:
短暂(ephemeral)(断开连接自己删除)
持久(persistent)(断开连接不删除)
2/Znode有四种形式的目录节点(默认是persistent )
PERSISTENT
PERSISTENT_SEQUENTIAL(持久序列/test0000000019 )
EPHEMERAL
EPHEMERAL_SEQUENTIAL
3/创建znode时设置顺序标识,znode名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护
4/在分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序
客户端应用可以在节点上设置监视器
三.Zookeeper 客户端API
1. 基本使用
org.apache.zookeeper.Zookeeper是客户端入口主类,负责建立与server的会话
它提供以下几类主要方法 :
功能 | 描述 |
create | 在本地目录树中创建一个节点 |
delete | 删除一个节点 |
exists | 测试本地是否存在目标节点 |
get/set data | 从目标节点上读取 / 写数据 |
get/set ACL | 获取 / 设置目标节点访问控制列表信息 |
get children | 检索一个子节点上的列表 |
sync | 等待要被传送的数据 |
2. api代码演示
public class SimpleZkClient {
private static final String connectString = "mini1:2181,mini2:2181,mini3:2181";
private static final int sessionTimeout = 2000;
// latch就相当于一个对象锁,当latch.await()方法执行时,方法所在的线程会等待
// 当latch的count减为0时,将会唤醒等待的线程
CountDownLatch latch = new CountDownLatch(1);
ZooKeeper zkClient = null;
@Before
public void init() throws Exception {
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
// 事件监听回调方法
@Override
public void process(WatchedEvent event) {
if (latch.getCount() > 0 && event.getState() == KeeperState.SyncConnected) {
System.out.println("countdown");
latch.countDown();
}
// 收到事件通知后的回调函数(应该是我们自己的事件处理逻辑)
System.out.println(event.getType() + "---" + event.getPath());
System.out.println(event.getState());
}
});
latch.await();
/*
* States state = zkClient.getState(); while(state!=States.CONNECTED){
* Thread.sleep(1000); }
*/
}
/**
* 数据的增删改查
*
* @throws InterruptedException
* @throws KeeperException
*/
// 创建数据节点到zk中
@Test
public void testCreate() throws KeeperException, InterruptedException {
// 参数1:要创建的节点的路径 参数2:节点大数据 参数3:节点的权限 参数4:节点的类型
String nodeCreated = zkClient.create("/eclipse", "hellozk".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
// 上传的数据可以是任何类型,但都要转成byte[]
zkClient.close();
}
// 判断znode是否存在
@Test
public void testExist() throws Exception {
Stat stat = zkClient.exists("/eclipse", false);
System.out.println(stat == null ? "not exist" : "exist");
}
// 获取子节点
@Test
public void getChildren() throws Exception {
List<String> children = zkClient.getChildren("/", true);
for (String child : children) {
System.out.println(child);
}
Thread.sleep(Long.MAX_VALUE);
}
// 获取znode的数据
@Test
public void getData() throws Exception {
byte[] data = zkClient.getData("/eclipse", true, null);
System.out.println(new String(data));
Thread.sleep(Long.MAX_VALUE);
}
// 删除znode
@Test
public void deleteZnode() throws Exception {
// 参数2:指定要删除的版本,-1表示删除所有版本
zkClient.delete("/eclipse", -1);
}
// 删除znode
@Test
public void setData() throws Exception {
zkClient.setData("/app1", "imissyou angelababy".getBytes(), -1);
byte[] data = zkClient.getData("/app1", false, null);
System.out.println(new String(data));
}
}
public class TestZKclient {
static ZooKeeper zk = null;
public static void main(String[] args) throws Exception {
final CountDownLatch countDownLatch = new CountDownLatch(1);
zk = new ZooKeeper("mini1:2181", 2000, new Watcher() {
@Override
public void process(WatchedEvent event) {
if (event.getState() == KeeperState.SyncConnected) {
countDownLatch.countDown();
}
System.out.println(event.getPath());
System.out.println(event.getType());
try {
zk.getChildren("/myboys", true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
countDownLatch.await();
/*
* zk.create("/myboys", "丑陋型".getBytes("UTF-8"), Ids.OPEN_ACL_UNSAFE,
* CreateMode.PERSISTENT); zk.close();
*/
/*
* byte[] data = zk.getData("/myboys", true, null);
* System.out.println(new String(data,"UTF-8"));
*
* Thread.sleep(Long.MAX_VALUE);
*/
/*List<String> children = zk.getChildren("/myboys", true);
for (String child : children) {
System.out.println(child);
}*/
/*zk.delete("/myboys/wangkai", -1);*/
/*zk.setData("/myboys","sldakfjsd".getBytes(),-1);*/
Stat stat = zk.exists("/mywives", true);
System.out.println(stat==null?"确实不存在":"存在");
zk.close();
}
}