Zookeeper的Java API操作

本文详细介绍了使用Curator Framework在Zookeeper中创建连接、添加和删除节点、修改数据、查询节点以及通过Watcher实现事件监听的基本操作,包括ExponentialBackoffRetry重试策略的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Curator常用操作:创建连接添加节点删除节点修改节点查询节点Watch事件监听
首先还是创建项目所需要的环境

1、在IDEA中创建maven工程
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.6.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>2.14.1</version>
        </dependency>
    </dependencies>
2、创建连接

第一种方式创建连接

CuratorFramework client = CuratorFrameworkFactory.newClient(
                "192.168.42.133:2181,192.168.42.134:2181",
                60 * 1000,
                15 * 1000,
                retryPolicy
        );
client.start();//开启连接

首先了解newClient()方法的四大参数的意义以及newClient()方法的原型

public static CuratorFramework newClient(String connectString, int sessionTimeoutMs, int connectionTimeoutMs, RetryPolicy retryPolicy) {
        return builder().connectString(connectString).sessionTimeoutMs(sessionTimeoutMs).connectionTimeoutMs(connectionTimeoutMs).retryPolicy(retryPolicy).build();
}

String connectString:连接字符串,zk server地址和端口
int sessionTimeoutMs:会话超时时间 单位ms(连接建立后,zookeeper的客户端服务端通信时没连通超时)
int connectionTimeoutMs:连接超时时间 单位ms
RetryPolicy retryPolicy:重试策略

重试策略含义解释
ExponentialBackoffRetry多久重试一次,重试多少次(两个参数,多久,几次)
RetryForever一直重试
RetryOneTime重试一次
RetryNTimes重试多次

运行结果:

2021-12-06 23:38:59,554 0      [           main] INFO  org.apache.zookeeper.ZooKeeper  - Client environment:zookeeper.version=3.6.2--803c7f1a12f85978cb049af5e4ef23bd8b688715, built on 09/04/2020 12:44 GMT
2021-12-06 23:38:59,589 35     [           main] INFO  org.apache.zookeeper.ZooKeeper  - Client
2021-12-06 23:38:59,590 36     [           main] INFO  org.apache.zookeeper.ZooKeeper  - Client environment:java.io.tmpdir=C:\Users\ADMINI~1\AppData\Local\Temp\
2021-12-06 23:38:59,590 36     [           main] INFO  org.apache.zookeeper.ZooKeeper  - Client environment:java.compiler=<NA>
2021-12-06 23:38:59,590 36     [           main] INFO  org.apache.zookeeper.ZooKeeper  - Client environment:os.name=Windows 10
2021-12-06 23:38:59,590 36     [           main] INFO  org.apache.zookeeper.ZooKeeper  - Client environment:os.arch=amd64
2021-12-06 23:38:59,590 36     [           main] INFO  org.apache.zookeeper.ZooKeeper  - Client environment:os.version=10.0
2021-12-06 23:38:59,590 36     [           main] INFO  org.apache.zookeeper.ZooKeeper  - Client environment:user.name=Administrator
2021-12-06 23:38:59,590 36     [           main] INFO  org.apache.zookeeper.ZooKeeper  - Client environment:user.home=C:\Users\Administrator
2021-12-06 23:38:59,590 36     [           main] INFO  org.apache.zookeeper.ZooKeeper  - Client environment:user.dir=D:\zookeeper
2021-12-06 23:38:59,590 36     [           main] INFO  org.apache.zookeeper.ZooKeeper  - Client environment:os.memory.free=101MB
2021-12-06 23:38:59,590 36     [           main] INFO  org.apache.zookeeper.ZooKeeper  - Client environment:os.memory.max=1788MB
2021-12-06 23:38:59,590 36     [           main] INFO  org.apache.zookeeper.ZooKeeper  - Client environment:os.memory.total=121MB
2021-12-06 23:38:59,639 85     [           main] INFO  work.imps.CuratorFrameworkImpl  - Starting
2021-12-06 23:38:59,644 90     [           main] DEBUG curator.CuratorZookeeperClient  - Starting
2021-12-06 23:38:59,644 90     [           main] DEBUG apache.curator.ConnectionState  - Starting
2021-12-06 23:38:59,644 90     [           main] DEBUG apache.curator.ConnectionState  - reset
2021-12-06 23:38:59,649 95     [           main] INFO  org.apache.zookeeper.ZooKeeper  - Initiating client connection, connectString=192.168.42.133:2181,192.168.42.134:2181 sessionTimeout=60000 watcher=org.apache.curator.ConnectionState@5f9d02cb
2021-12-06 23:38:59,664 110    [           main] INFO  ache.zookeeper.common.X509Util  - Setting -D jdk.tls.rejectClientInitiatedRenegotiation=true to disable client-initiated TLS renegotiation
2021-12-06 23:39:00,474 920    [           main] INFO  che.zookeeper.ClientCnxnSocket  - jute.maxbuffer value is 1048575 Bytes
2021-12-06 23:39:00,494 940    [           main] INFO  rg.apache.zookeeper.ClientCnxn  - zookeeper.request.timeout value is 0. feature enabled=false
2021-12-06 23:39:00,507 953    [           main] INFO  work.imps.CuratorFrameworkImpl  - Default schema

第二种创建连接方式

CuratorFrameworkFactory client = CuratorFrameworkFactory.builder().connectString("192.168.42.133:2181,192.168.42.134:2181")
                .sessionTimeoutMs(60*1000)
                .connectionTimeoutMs(15*1000)
                .retryPolicy(retryPolicy)
                .namespace("temp")
                .build();
client.start();     

其中namespace("temp")表示是每次在该temp目录下创建节点

单纯是从上面还是无法明显的效果,接下来我们开始创建些节点

3、添加节点

在添加节点前的zookeeper:

[zookeeper]
[zk: localhost:2181(CONNECTED) 14] 
    @Test
    public void init() throws Exception {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,10);
        CuratorFramework client = CuratorFrameworkFactory.newClient(
                "192.168.42.133:2181,192.168.42.134:2181",
                60 * 1000,
                15 * 1000,
                retryPolicy
        );
        client.start();//开启连接
        String s = client.create().forPath("/abc", "1234".getBytes());
        System.out.println(s);
    }
}

执行完上面的代码,zookeeper的节点:

[zk: localhost:2181(CONNECTED) 14] ls /
[temp, zookeeper]
[zk: localhost:2181(CONNECTED) 15] get -s /temp 
1234
cZxid = 0x800000011
ctime = Mon Dec 06 08:29:41 PST 2021
mZxid = 0x800000011
mtime = Mon Dec 06 08:29:41 PST 2021
pZxid = 0x800000011
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0

如果创建节点,没有设置数据,就会把当前的IP设置为默认的值在加上client.create().forPath("/abc");该代码的话,再获取/abc节点的值,发现是IP地址值

[zk: localhost:2181(CONNECTED) 18] get /abc
192.168.73.1

创建节点不是有两种:持久的临时的以及是有序的无序的,上面的创建都是默认是持久的节点
client.create().withMode(CreateMode.EPHEMERAL).forPath("/abc1");withMode设置节点的类型,CreateMode是一个枚举类,如果是临时的,只要一次运行结束,再在zookeeper上查看还是无法看到的,一次会话结束节点就会删除

创建多级的节点
client.create().creatingParentContainersIfNeeded().forPath("/a/c/d","acd".getBytes());

总结创建节点:

基本操作代码
基本创建create().forPath("/abc") 默认的值是IP地址
创建节点带数据create().forPath("/abc",“acv”.getBytes())
设置节点的类型create().withMode(CreateMode.EPHEMERAL).forPath("")
创建多级节点create().creatingParentContainersIfNeeded().forPath("/a/c/d",“acd”.getBytes());
4、删除节点
分类代码
删除单个节点client.delete().forPath("/temp")
删除有子节点的节点client.delete().deletingChildrenIfNeeded().forPath("/");
必须成功的删除client.delete().guaranteed().deletingChildrenIfNeeded().forPath("/abc")
删除带有回调函数client.delete().guaranteed().inBackground(new BackgroundCallback()
4.1、删除单个节点

java代码:

@Test
public void TestDelete() throws Exception {
	client.delete().forPath("/temp");
}
[zk: localhost:2181(CONNECTED) 1] ls /temp 
[]
[zk: localhost:2181(CONNECTED) 2] get /temp 
1234
[zk: localhost:2181(CONNECTED) 3] ls /
[a, abc, zookeeper]
4.2、删除有子节点的节点

java代码:

@Test
public void TestDeleteWithNode() throws Exception {
	client.delete().deletingChildrenIfNeeded().forPath("/");
}
[zk: localhost:2181(CONNECTED) 3] ls /
[a, abc, zookeeper]
[zk: localhost:2181(CONNECTED) 4] ls /
[a, abc, zookeeper]
[zk: localhost:2181(CONNECTED) 5] ls /a
[c]
[zk: localhost:2181(CONNECTED) 6] ls /a/c
[d]
[zk: localhost:2181(CONNECTED) 7] ls /
[abc, zookeeper]
4.3、必须成功的删除

java代码:

@Test
public void TestDeleteguaranteed() throws Exception {
	client.delete().guaranteed().deletingChildrenIfNeeded().forPath("/abc");
}
[zk: localhost:2181(CONNECTED) 8] ls /
[abc, zookeeper]
[zk: localhost:2181(CONNECTED) 9] ls /abc 
[]
[zk: localhost:2181(CONNECTED) 10] ls /
[zookeeper]
4.3、必须成功的删除

java代码:

@Test
public void TestDeletebackFunction() throws Exception {
	client.delete().guaranteed().inBackground(new BackgroundCallback() {
	public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) 	throws Exception {
		System.out.println(curatorEvent);
	}
	}).forPath("/temp");
}
5、修改节点

比较简单:
client.setData().forPath("/a","abc3".getBytes());但是有个问题就是如果多个对数据进行修改就会出现问题,这时需要修改之前需要查询版本号

// client是连接
Stat stat1 = new Stat();
client.getData().storingStatIn(stat1).forPath("/abc");
int version = stat1.getVersion();
client.setData().withVersion(version).forPath("/abc");

保证了原子性的操作

6、查询节点
查询节点get代码实现
查询数据getbyte[] bytes = client.getData().forPath("/abc"); System.out.println(bytes.toString());
查询子节点lsList<String> list = client.getChildren().forPath("/");
查询节点状态信息ls -sStat stat = new Stat(); client.getData().storingStatIn(stat).forPath("/a");
7、Watch事件监听

Zookeeper允许用户在指定节点注册一些Watcher,并且在一些特定事件触发的时候,Zookeeper服务端会将事件通知到响应的客户端,Zookeeper中引入了Wathcer机制来实现发布/订阅功能,能够让多个订阅者同时监听某一个对象(节点),当一个对象自身状态变化时,会通知所有订阅者。
Curator引入了Cache来实现对Zookeeper服务器事件的监听
Zookeeper提供三种Watcher:

  • NodeCache只是监听一个特定的节点
  • PathChildrenCache监控一个Node的所有子节点
  • TreeCache:可以监控整个树上的所有节点,包括自己
7.1、NodeCache 监听一个节点

java代码:

	@Test
    public void TestWatch() throws Exception {
        // 监听一个节点
        // 1、创建NodeCache对象
        final NodeCache nodeCache = new NodeCache(client,"/temp");
        nodeCache.start(true);
        // 2、注册监听
        nodeCache.getListenable().addListener(new NodeCacheListener() {
            public void nodeChanged() throws Exception {
                System.out.println("节点变化了....");
                byte[] data = nodeCache.getCurrentData().getData();
                System.out.println(new String(data));
            }
        });
        // 3、开启监听,如果设置为true,则是开启监听时加载缓存
        // 程序结束就无效果
        while (true){

        }
    }

监听事件发生后触发:new NodeCacheListener(){ }
输出信息:

2021-12-07 16:54:39,748 18770  [68.42.134:2181)] DEBUG rg.apache.zookeeper.ClientCnxn  - Got notification sessionid:0x4000107285d0001
2021-12-07 16:54:39,748 18770  [68.42.134:2181)] DEBUG rg.apache.zookeeper.ClientCnxn  - Got WatchedEvent state:SyncConnected type:NodeDataChanged path:/temp for sessionid 0x4000107285d0001
2021-12-07 16:54:39,761 18783  [68.42.134:2181)] DEBUG rg.apache.zookeeper.ClientCnxn  - Reading reply sessionid:0x4000107285d0001, packet:: clientPath:/temp serverPath:/temp finished:false header:: 9,3  replyHeader:: 9,47244640267,0  request:: '/temp,T  response:: s{47244640259,47244640267,1638867170774,1638867279705,3,0,0,0,6,0,47244640259} 
2021-12-07 16:54:39,763 18785  [68.42.134:2181)] DEBUG rg.apache.zookeeper.ClientCnxn  - Reading reply sessionid:0x4000107285d0001, packet:: clientPath:/temp serverPath:/temp finished:false header:: 10,4  replyHeader:: 10,47244640267,0  request:: '/temp,T  response:: #313233343536,s{47244640259,47244640267,1638867170774,1638867279705,3,0,0,0,6,0,47244640259} 
节点变化了....
123456

如果是删除的话,就无法获取数据会报错:

2021-12-07 16:57:39,430 20770  [ain-EventThread] ERROR mework.recipes.cache.NodeCache  - Calling listener
java.lang.NullPointerException
7.2、PathChildrenCache 监听父节点的所有子节点

java代码:

	@Test
    public void TestPathChildren() throws Exception {
        // 第三个参数是是否把数据缓存
        PathChildrenCache path = new PathChildrenCache(client, "/a", true);
        path.getListenable().addListener(new PathChildrenCacheListener() {
            public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent event) throws Exception {
                System.out.println("/a下的子节点变化了...");
                System.out.println(event);
                if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){
                    System.out.println("子节点的数据发生更新");
                    System.out.println(event.getData().getData());
                }
            }
        });
        path.start(true);

        while (true){

        }

    }

PathChildrenCache path = new PathChildrenCache(client, “/a”, true);
第二个参数:是路径父节点
第三个参数:是否把数据缓存
输出信息:

/a下的子节点变化了...
PathChildrenCacheEvent{type=CHILD_ADDED, data=ChildData{path='/a/b', stat=47244640271,47244640271,1638867926344,1638867926344,0,0,0,0,0,0,47244640271
, data=null}}
2021-12-07 17:20:28,088 1023   [68.42.134:2181)] DEBUG rg.apache.zookeeper.ClientCnxn  - Reading reply sessionid:0x4000107285d0003, packet:: clientPath:null serverPath:null finished:false header:: 6,4  replyHeader:: 6,47244640275,0  request:: '/a/b,F  response:: ,s{47244640271,47244640271,1638867926344,1638867926344,0,0,0,0,0,0,47244640271} 
2021-12-07 17:20:28,088 1023   [68.42.134:2181)] DEBUG rg.apache.zookeeper.ClientCnxn  - Reading reply sessionid:0x4000107285d0003, packet:: clientPath:/a/c serverPath:/a/c finished:false header:: 7,4  replyHeader:: 7,47244640275,0  request:: '/a/c,T  response:: ,s{47244640272,47244640272,1638867928929,1638867928929,0,0,0,0,0,0,47244640272} 
/a下的子节点变化了...
PathChildrenCacheEvent{type=CHILD_ADDED, data=ChildData{path='/a/c', stat=47244640272,47244640272,1638867928929,1638867928929,0,0,0,0,0,0,47244640272
, data=null}}
2021-12-07 17:20:28,089 1024   [68.42.134:2181)] DEBUG rg.apache.zookeeper.ClientCnxn  - Reading reply sessionid:0x4000107285d0003, packet:: clientPath:/a/d serverPath:/a/d finished:false header:: 8,4  replyHeader:: 8,47244640275,0  request:: '/a/d,T  response:: ,s{47244640273,47244640273,1638867931748,1638867931748,0,0,0,0,0,0,47244640273} 
/a下的子节点变化了...
PathChildrenCacheEvent{type=CHILD_ADDED, data=ChildData{path='/a/d', stat=47244640273,47244640273,1638867931748,1638867931748,0,0,0,0,0,0,47244640273
, data=null}}
7.3、TreeCache 监听子节点或者父节点的信息变化

java代码:

	@Test
    public void TestWatchTreeCache() throws Exception {
        TreeCache treeCache = new TreeCache(client, "/a");
        treeCache.getListenable().addListener(new TreeCacheListener() {
            public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent event) throws Exception {
                System.out.println("treeCache:子节点或者父节点的监听");
                System.out.println(event);
                if(event.getType().equals(TreeCacheEvent.Type.NODE_UPDATED)){
                    System.out.println("子节点或者父节点数据更新了....");
                    System.out.println(new String(event.getData().getData()));
                }
            }
        });
        treeCache.start();
        while (true){

        }
    }

后台输出的信息:

treeCache:子节点或者父节点的监听
TreeCacheEvent{type=NODE_ADDED, data=ChildData{path='/a/d', stat=47244640273,47244640273,1638867931748,1638867931748,0,0,0,0,0,0,47244640273
, data=null}}
2021-12-07 17:30:18,815 2478   [ain-EventThread] DEBUG mework.recipes.cache.TreeCache  - processResult: CuratorEventImpl{type=CHILDREN, resultCode=0, path='/a/d', name='null', children=[], context=null, stat=47244640273,47244640273,1638867931748,1638867931748,0,0,0,0,0,0,47244640273
, data=null, watchedEvent=null, aclList=null}
2021-12-07 17:30:18,815 2478   [ain-EventThread] DEBUG mework.recipes.cache.TreeCache  - publishEvent: TreeCacheEvent{type=INITIALIZED, data=null}
treeCache:子节点或者父节点的监听
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值