Zookeeper CuratorFramework 框架的使用

本文深入解析CuratorFramework框架连接Zookeeper服务的过程,详细介绍了如何配置连接参数、重连策略及会话超时时间。文章还阐述了Zookeeper中不同类型的节点属性,包括持久化节点、临时节点、持久化时序节点和临时时序节点的特点和应用场景。同时,通过代码示例展示了如何使用CuratorFramework进行节点操作和实现节点监听,包括监听节点数据变化和子节点的增删改。

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

CuratorFramework 是Netflix公司开发一款连接zookeeper服务的框架,提供了比较全面的功能,除了基础的节点的操作,节点的监听,还有集群的连接以及重试。
首先是创建一个连接
RetryPolicy policy = new ExponentialBackoffRetry(1000, 10);

    //通过工厂创建Curator
    CuratorFramework curator = CuratorFrameworkFactory.builder().connectString("127.0.0.1:2184").sessionTimeoutMs(10000).retryPolicy(policy).build();
    
curator.start();

该方法配置重连retryPolicy以及回话有效时间sessionTimeoutMs,重连就是当客户端与zookeeper 连接异常的时候,如网络波动,断开链接,支持重新连接,会话有效这个与节点的属性有关。那么zookeeper 有哪些节点属性。
Zookeeper 有4种节点属性,持久化节点PERSISTENT,临时节点EPHEMERAL,持久化时序节点PERSISTENT_SEQUENTIAL,临时时序节点EPHEMERAL_SEQUENTIAL

持久化节点:一般通过curator.create().forPath("/PATH") 代码创建的节点默认是持久化节点,持久化节点就是不论链接是否断开以及回话是否失效,都不会删除
临时节点:
curator.create().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath("/PATH");

上面代码通过create时候指定创建的节点类型为临时节点,临时节点就是链接断开或者回话失效就是sessionTimeoutMs 配置的时间内,会话就失效了,那么该节点就删除了。例如上面代码指定的时间为10000毫秒,当10s 后会话失效创建的PATH节点自动删除。临时节点很有作用。例如当有一个主服务,多个备用服务,当主服务挂掉后,想启用备用服务,可以利用zookeeper 临时节点这个功能,当服务挂掉,zookeeper节点删除,通过节点监听功能,启用备用服务,而保证服务正常。
持久化时序节点:
curator.create().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath("/PATH");

这个和持久化代码的区别就是,当节点是创建了一个持久化节点PATH,然后在创建就会抛出一个节点已经存在的异常。 而当使用上面创建时序节点的代码,就会创建一个创建一个PATH0000000021的节点,而且可以创建多个。
临时持久化节点就不用说了,就是有时间限制的持久化时序节点。
一般使用的都是持久化节点和备用节点,时序节点很少使用。
CuratorFramework 节点的操作
curator.create().for("/PATH") // 创建节点
curator.getData().for("/PATH") // 获取节点数据
curator.setData().for("/PATH") // 节点赋值
curator.checkExist().for("/PATH") // 判断是否存在该节点

CuratorFramework 提供了节点的监听功能,当节点数据变化,修改,会调用注册监听事件。一般使用比较多的是两个监听事件NodeCacheListener和 PathChildrenCacheListener,监听事件需要通过创建节点缓存,然后在节点缓存里面添加监听事件。这两个监听事件的区别是第一个监听本节点,只能监听节点数据的变化,无法监听节点的删除,PathChildrenCacheListener监听的本节点的子节点的变化,包括数据修改以及节点的添加删除。
通过代码来了解下这两个监听器的使用
package com.client;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.framework.recipes.cache.NodeCacheListener;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCache.StartMode;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

public class ClientSingleWatch {

public static void main(String[] args) throws Exception{
	
    RetryPolicy policy = new ExponentialBackoffRetry(1000, 10);
    
    //通过工厂创建Curator
    CuratorFramework curator = CuratorFrameworkFactory.builder().connectString("127.0.0.1:2181")
            .sessionTimeoutMs(2000).retryPolicy(policy).build();
    
    curator.start();
    
    watchChild(curator, "/PATH");
    
    watch(curator, "/PATH");
  
    while(true){
    	
    }
    
}

//创建本节点数据变化监听事件
public static void watch(CuratorFramework curator, String path) throws Exception{
	final  NodeCache nodeCache = new NodeCache(curator, path, false);
    nodeCache.getListenable().addListener(new NodeCacheListener() {
        @Override
        public void nodeChanged() throws Exception {
        	System.out.println("开始监听本级节点-----");
        	System.out.println("监听的节点为" + nodeCache.getCurrentData().getPath() + "数据变为 : "+new String(nodeCache.getCurrentData().getData()));
           
        }
    });
    nodeCache.start();
}

//创建本节点的子节点监听事件
public static void watchChild(CuratorFramework curator, String path) throws Exception{
	PathChildrenCache childrenCache = new PathChildrenCache(curator, path, true);
    PathChildrenCacheListener childrenCacheListener = new PathChildrenCacheListener() {

		@Override
		public void childEvent(CuratorFramework client,
				PathChildrenCacheEvent event) throws Exception {
			System.out.println("开始监听子节点:-----");
            ChildData data = event.getData();
            switch (event.getType()) {
            case CHILD_ADDED:
                System.out.println("CHILD_ADDED : "+ data.getPath() +"  数据:"+ data.getData());
                break;
            case CHILD_REMOVED:
                System.out.println("CHILD_REMOVED : "+ data.getPath() +"  数据:"+ data.getData());
                break;
            case CHILD_UPDATED:
                System.out.println("CHILD_UPDATED : "+ data.getPath() +"  数据:"+ new String(data.getData()));
                break;
            default:
                break;
            }
			
		}
        
    };
    
    childrenCache.getListenable().addListener(childrenCacheListener);
    System.out.println("Register zk watcher successfully!");
    childrenCache.start(StartMode.POST_INITIALIZED_EVENT);
}

}
上面代码两个方法watch 和 watchChild分别注册两个监听事件,第一个监听PATH本级节点数据变化,第二个监听了PATH 子级节点时候有新增删除修改。在main方法里面写了个死循环,保证持续监听。启动后在zookeeper 节点树上有一个PATH节点,这里说明下启动监听,如果不存在节点会创建一个没有数据的节点,启动后控制台输出如下,
Register zk watcher successfully!
开始监听子节点:-----
开始监听子节点:-----
开始监听本级节点-----
监听的节点为/PATH数据变为 :

然编写一个对节点进行修改删除的main方法

package com.client;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;

public class ZookeeperClient4 {

public static void main(String[] args) throws Exception{
	// TODO Auto-generated method stub
	
	//
	RetryPolicy policy = new ExponentialBackoffRetry(1000, 10);
    
    //通过工厂创建Curator
    CuratorFramework curator = CuratorFrameworkFactory.builder().connectString("127.0.0.1:2184")
            .sessionTimeoutMs(10000).retryPolicy(policy).build();
    
    curator.start();
    
  
    
    curator.setData().forPath("/PATH", "333".getBytes());
    
    curator.create().forPath("/PATH/TEST");
    curator.setData().forPath("/PATH/TEST", "4444".getBytes());
    
    curator.delete().forPath("/PATH/TEST");

}

}
启动这个main方法,
可以看到监听main方法输出了以下几行
开始监听本级节点-----
监听的节点为/PATH数据变为 : 333
开始监听子节点:-----
CHILD_ADDED : /PATH/TEST 数据:192.168.43.234
开始监听子节点:-----
CHILD_UPDATED : /PATH/TEST 数据:4444
开始监听子节点:-----
CHILD_REMOVED : /PATH/TEST 数据:4444
分析代码
curator.setData().forPath("/PATH", “333”.getBytes()); 这行代码向PATH节点添加输出,触发了监听本级节点方法,输出了”监听的节点为/PATH数据变为 : 333
”,
curator.create().forPath("/PATH/TEST"); 这行代码在PATH 下创建一个TEST 子节点,触发了监听PATH子节点的方法。该监听可以获取子节点的几种操作CHILD_ADDED,CHILD_REMOVED,CHILD_UPDATED,分别是节点新增,节点修改,节点删除,那么新增以后触发监听event的type类型为CHILD_ADDED,修改以后触发监听event的type类型为CHILD_UPDATED,删除以后触发监听event的type类型为CHILD_UPDATED,
到这,关于zookeeper所有节点相关操作都介绍完了,下节将介绍分布式环境下zookeeper节点监听,以及监听可以解决何种业务场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值