zookeeper(四)客户端curator

curator

curator是Netflix开源的一个zookeeper客户端,后来捐给apache。curator框架在zookeeper原生API接口上进行了包装,解决了很多zookeeper客户端非常底层的细节开发。提供zookeeper各种应用场景(分布式锁、集群领导选举、共享计数器、缓存机制、分布式队列等)的抽象封装,实现了Fluent风格的API接口,是最流行的zookeeper客户端。

原生zookeeperAPI的不足:

  • 连接对象异步创建,需要开发人员自行编码等待
  • 连接没有自动超时重连机制
  • watcher一次注册只能生效一次
  • 不支持递归创建树形结点

curator的特点:

  • 解决session会话超时重连
  • watcher可以反复注册
  • 简化API使用
  • 支持Fluent风格
  • 提供了分布式锁服务、共享计数器、缓存等机制

依赖

<!-- Apache下的Zookeeper架包-->
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.5.5</version>
</dependency>
<!--curator-->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>2.6.0</version>
    <exclusions>
        <exclusion>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>2.6.0</version>
</dependency>

使用curator连接zookeeper

public static void main(String[] args) {
CuratorFramework client = CuratorFrameworkFactory.builder()
        //集群用逗号隔开
        .connectString("192.168.63.129:2181")
        //超时时间
        .sessionTimeoutMs(5000)
        //重连机制,超时3秒重连一次
        //RetryOneTime 指定时间后重连一次
        //RetryNTimes 指定时间重连n次
        //RetryUntilElapsed 每隔指定时间后重连一次,不能超过设置总时间
        //ExponentialBackoffRetry 重连n次,时间基于参数计算,越来越长
        .retryPolicy(new RetryOneTime(3000))
        //指定命名空间
        .namespace("create")
        //构建连接
        .build();
//打开连接
client.start();

System.out.println(client.isStarted() ? "连接成功" : "连接失败");

//关闭连接
client.close();
}

工具类:

public class CuratorUtil {
    private static CuratorFramework client=null;
    public static CuratorFramework Connect(){
        client = CuratorFrameworkFactory.builder()
                //集群用逗号隔开
                .connectString("192.168.63.129:2181")
                //超时时间
                .sessionTimeoutMs(5000)
                //重连机制,超时3秒重连一次
                //RetryOneTime 指定时间后重连一次
                //RetryNTimes 指定时间重连n次
                //RetryUntilElapsed 每隔指定时间后重连一次,不能超过设置总时间
                //ExponentialBackoffRetry 重连n次,时间基于参数计算,越来越长
                .retryPolicy(new RetryOneTime(3000))
                //指定命名空间
                .namespace("create")
                //构建连接
                .build();
        //打开连接
        client.start();
        return client;
    }
    public static void close(){
        if (client!=null){
            //关闭连接
            client.close();
        }
    }
}

新增结点 create

public static void main(String[] args) {
        CuratorFramework client = CuratorUtil.Connect();
        System.out.println(client.isStarted()?"连接成功":"连接失败");
        try {
            //创建持久化节点
            String s = client.create()
                    //创建持久化节点
                    .withMode(CreateMode.PERSISTENT)
                    //权限列表为 world:anyone:cdrwa
                    .withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
                    //arg1结点路径 arg2结点数据 由于指定了命名空间 会创建/create/node1
                    .forPath("/node2", "aaa".getBytes());
            //返回节点路径"/node2"
            System.out.println(s);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            CuratorUtil.close();
        }
    }

自定义权限列表

@BeforeEach
public  void connect(){
    client = CuratorUtil.Connect();
}
@AfterEach
public void close(){
    client.close();
}
//自定义权限
@Test
public void test01() throws Exception {
    //自定义权限列表
    List<ACL> list=new ArrayList<>();
    Id id=new Id("ip","192.168.63.129");
    list.add(new ACL(ZooDefs.Perms.ALL,id));
    //新增结点
    client.create()
            .withMode(CreateMode.PERSISTENT)
            .withACL(list)
            .forPath("/node3","2020GetGoodOffer".getBytes());
}

递归创建

//递归创建
@Test
public void test02() throws Exception {
    client.create()
            //如果父路径不存在则创建
            .creatingParentsIfNeeded()
            .withMode(CreateMode.PERSISTENT)
            .withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
            .forPath("/node3/node31","2020GetGoodOffer".getBytes());
}

异步创建

//异步创建
@Test
public void create4() throws Exception{
    //异步创建
    client.create()
            //如果父路径不存在则创建
            .creatingParentsIfNeeded()
            .withMode(CreateMode.PERSISTENT)
            .withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
            //异步回调方法
            .inBackground(new BackgroundCallback() {
                @Override
                public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) {
                    System.out.println("结点路径"+curatorEvent.getPath());
                    System.out.println("事件类型"+curatorEvent.getType());
                }
            })
            .forPath("/node4","2020GetGoodOffer".getBytes());
    //防止异步回调还没执行完,程序就结束了
    Thread.sleep(5000);
}

更改结点 setData

@BeforeEach
public  void connect(){
    client = CuratorUtil.Connect();
}
@AfterEach
public void close(){
    client.close();
}
//更新节点
@Test
public void set01() throws Exception {
    client.setData().forPath("/node1","bbb".getBytes());
}
//使用版本号更新
@Test
public void set2() throws Exception{
    //使用版本号更新 -1代表不参与
    client.setData()
            //-1不更新版本号
            .withVersion(0)
            .forPath("/node2","2020GetGoodOffer".getBytes());
}
//异步修改
@Test
public void set3() throws Exception{
    client.setData()
            .withVersion(0)
            .inBackground(new BackgroundCallback() {//异步回调方法
                @Override
                public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) {
                    System.out.println("结点路径"+curatorEvent.getPath());
                    System.out.println("事件类型"+curatorEvent.getType());
                }
            })
            .forPath("/node4","hahah".getBytes());
    Thread.sleep(5000);
}

删除结点 delete

@BeforeEach
public  void connect(){
    client = CuratorUtil.Connect();
}
@AfterEach
public void close(){
    client.close();
}
//删除节点
@Test
public void del01() throws Exception {
    client.delete().forPath("/node4");
}
//使用版本号删除
@Test
public void del2() throws Exception{
    //使用版本号删除 -1代表不参与
    client.delete()
            //-1不更新版本号
            .withVersion(1)
            .forPath("/node2");
}
//递归删除
@Test
public void del3() throws Exception{
      client.delete()
              .deletingChildrenIfNeeded()
              .forPath("/node3");
}
//异步删除
@Test
public void del4() throws Exception{
    client.delete()
            .withVersion(-1)
            .inBackground(new BackgroundCallback() {//异步回调方法
                @Override
                public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) {
                    System.out.println("结点路径"+curatorEvent.getPath());
                    System.out.println("事件类型"+curatorEvent.getType());
                }
            })
            .forPath("/node4");
    Thread.sleep(5000);
}

查看结点 get

@BeforeEach
public  void connect(){
    client = CuratorUtil.Connect();
}
@AfterEach
public void close(){
    client.close();
}
//读取结点
@Test
public void get01() throws Exception {
    byte[] node1s = client.getData().forPath("node1");
    System.out.println(new String(node1s));
}
//读取数据时读取结点属性
@Test
public void get2() throws Exception{
    Stat stat=new Stat();
    byte[] bytes = client.getData()
            .storingStatIn(stat)
            .forPath("/node1");
    System.out.println("node1:"+ new String(bytes));
    System.out.println("node1 version:"+stat.getVersion());
}
//异步读取
@Test
public void get3() throws Exception{
    Executor executor = Executors.newFixedThreadPool(2);
    client.getData()
            .inBackground((curatorFramework, curatorEvent) -> {
                System.out.println("结点路径:" + curatorEvent.getPath());
                System.out.println("事件类型:" + curatorEvent.getType());
                System.out.println("数据:"+new String(curatorEvent.getData()));
            },executor)
            .forPath("/node3");
    Thread.sleep(5000);
    System.out.println("结束");
}

读取子结点数据 getChildren

@BeforeEach
public  void connect(){
    client = CuratorUtil.Connect();
}
@AfterEach
public void close(){
    client.close();
}
//读取子结点
@Test
public void getChild1() throws Exception{
    List<String> list = client.getChildren()
            .forPath("/node3");
    System.out.println(list);
}
//读取数据时读取结点属性
@Test
public void getChild2() throws Exception{
    Stat stat=new Stat();
    client.getChildren()
            .storingStatIn(stat)
            .forPath("/node3");
}
//异步读取子节点
@Test
public void getChild3() throws Exception{
    client.getChildren()
            .inBackground(new BackgroundCallback() {//异步回调方法
                @Override
                public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) {
                    System.out.println("结点路径"+curatorEvent.getPath());
                    System.out.println("事件类型"+curatorEvent.getType());
                    System.out.println(curatorEvent.getChildren());
                }
            })
            .forPath("/node3");
    Thread.sleep(5000);
}

检查结点是否存在 checkExists

@BeforeEach
public  void connect(){
    client = CuratorUtil.Connect();
}
@AfterEach
public void close(){
    client.close();
}
//判断结点是否存在
@Test
public void exists1() throws Exception{
    Stat stat = client.checkExists()
            .forPath("/node1");
    //stat:370,385,1590978226504,1590980312872,1,0,0,0,3,0,370
    System.out.println("stat:"+stat);
}
//异步判断
@Test
public void exists2() throws Exception{
    client.checkExists()
            .inBackground(new BackgroundCallback() {//异步回调方法
                @Override
                public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) {
                    System.out.println("结点路径"+curatorEvent.getPath());
                    System.out.println("事件类型"+curatorEvent.getType());
                    System.out.println("判断结果:"+curatorEvent.getStat().getVersion());
                }
            })
            .forPath("/node1");
    Thread.sleep(5000);
}

watcher

NodeCache 监听特定结点

@BeforeEach
public  void connect(){
    client = CuratorUtil.Connect();
}
@AfterEach
public void close(){
    client.close();
}
//监听特定节点
@Test
public void watcher1() throws Exception{
    //监视某个结点 arg1连接对象 arg2监视路径
    NodeCache nodeCache=new NodeCache(client,"/watcher1");
    //启动监视器
    nodeCache.start();
    System.out.println("监视器已打开");
    nodeCache.getListenable().addListener(new NodeCacheListener() {
        @Override
        public void nodeChanged() throws Exception {
            System.out.println("结点路径: "+nodeCache.getCurrentData().getPath());
            System.out.println("结点数据: "+nodeCache.getCurrentData().getData());           
        }
    });
    Thread.sleep(150000);
    //关闭监视器
    nodeCache.close();
    System.out.println("监视器已关闭");
}

PathChildren Cache 监听子结点

//监听子节点
@Test
public void watcher2() throws Exception{
    //监视子结点 arg1 连接对象 arg2 监视路径 arg3 能否读取数据
    PathChildrenCache pathChildrenCache=new PathChildrenCache(client,"/watcher1",true);
    //启动监视器
    pathChildrenCache.start();
    System.out.println("监视器已打开");
    pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
        @Override
        public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) {
            System.out.println("结点事件类型 :"+pathChildrenCacheEvent.getType());
            System.out.println("结点的路径: "+pathChildrenCacheEvent.getData().getPath());
            System.out.println("结点数据: "+new String(pathChildrenCacheEvent.getData().getData()));
        }
    });
    Thread.sleep(150000);
    //关闭监视器
    pathChildrenCache.close();
    System.out.println("监视器已关闭");
}

新增子节点时:
结点事件类型 :CHILD_ADDED
结点的路径: /watcher1/w1
结点数据: 123

删除子节点时:
结点事件类型 :CHILD_REMOVED
结点的路径: /watcher1/w1
结点数据: 123

事务 inTransaction

//开启事务
@Test
public void tran2() throws Exception{
    client.inTransaction()
    		//创建一个节点
            .create().forPath("/node6","ccc".getBytes())
            .and()
            //更新一个不存在的节点,必然失败,更新和创建这两操作全回滚
            .setData().forPath("/node5","666".getBytes())
            .and()
            .commit();
}

分布式锁

分布式可重入排它锁

//分布式可重入排它锁
@Test
public void lock1() throws Exception{
    //排它锁
    InterProcessLock interProcessLock=new InterProcessMutex(client,"/lock1");
    System.out.println("等待获取锁对象");
    interProcessLock.acquire();
    for(int i=1;i<=10;i++){
        Thread.sleep(1000);
        System.out.println(i);
    }
    interProcessLock.release();
    System.out.println("等待释放锁");
}

同时启动两个客户端,启动配置:
在这里插入图片描述
客户端1:
在这里插入图片描述
当第一个客户端释放了锁,第二个才能继续:
在这里插入图片描述

分布式读写锁

读锁
//分布式读写锁
@Test
public void lock2() throws Exception{
    //读写锁
    InterProcessReadWriteLock interProcessReadWriteLock=new InterProcessReadWriteLock(client,"/lock1");
    InterProcessMutex interProcessLock = interProcessReadWriteLock.readLock();
    System.out.println("等待读锁对象");
    interProcessLock.acquire();
    for(int i=1;i<=10;i++){
        Thread.sleep(3000);
        System.out.println(i);
    }
    interProcessLock.release();
    System.out.println("等待释放锁");
}

两个客户端可以同时读,读锁是共享锁:
在这里插入图片描述
在这里插入图片描述

写锁
//写锁 写锁之间、写锁与读锁都是互斥的
@Test
public void lock3() throws Exception{
    InterProcessReadWriteLock interProcessReadWriteLock=new InterProcessReadWriteLock(client,"/lock1");
    InterProcessMutex interProcessLock = interProcessReadWriteLock.writeLock();
    System.out.println("等待写锁对象");
    interProcessLock.acquire();
    for(int i=1;i<=10;i++){
        Thread.sleep(1000);
        System.out.println(i);
    }
    interProcessLock.release();
    System.out.println("等待释放锁");
}

演示效果和分布式可重入排它锁一样。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数字乡村和智慧农业的数字化转型是当前农业发展的新趋势,旨在通过应用数字技术,实现农业全流程的再造和全生命周期的管理服务。中国政府高度重视这一领域的发展,提出“数字中国”和“乡村振兴”战略,以提升国家治理能力,推动城乡融合发展。 数字乡村的建设面临乡村治理、基础设施、产业链条和公共服务等方面的问题,需要分阶段实施《数字乡村发展战略纲要》来解决。农业数字化转型的需求包括满足市民对优质农产品的需求、解决产销对接问题、形成优质优价机制、提高农业劳动力素质、打破信息孤岛、提高农业政策服务的精准度和有效性,以及解决农业融资难的问题。 数字乡村建设的关键在于构建“1+3+4+1”工程,即以新技术、新要素、新商业、新农民、新文化、新农村为核心,推进数据融合,强化农业大数据的汇集功能。数字农业大数据解决方案以农业数字底图和数据资源为基础,通过可视化监管,实现区域农业的全面数字化管理。 数字农业大数据架构基于大数据、区块链、GIS和物联网技术,构建农业大数据中心、农业物联网平台和农村综合服务指挥决策平台三大基础平台。农业大数据中心汇聚各类涉农信息资源和业务数据,支持大数据应用。信息采集系统覆盖市、县、乡、村多级,形成高效的农业大数据信息采集体系。 农业物联网平台包括环境监测系统、视频监控系统、预警预报系统和智能控制系统,通过收集和监测数据,实现对农业环境和生产过程的智能化管理。综合服务指挥决策平台利用数据分析和GIS技术,为农业决策提供支持。 数字乡村建设包括三大服务平台:治理服务平台、民生服务平台和产业服务平台。治理服务平台通过大数据和AI技术,实现乡村治理的数字化;民生服务平台利用互联网技术,提供各类民生服务;产业服务平台融合政企关系,支持农业产业发展。 数字乡村的应用场景广泛,包括农业生产过程、农产品流通、农业管理和农村社会服务。农业生产管理系统利用AIoT技术,实现农业生产的标准化和智能化。农产品智慧流通管理系统和溯源管理系统提高流通效率和产品追溯能力。智慧农业管理通过互联网+农业,提升农业管理的科学性和效率。农村社会服务则通过数字化手段,提高农村地区的公共服务水平。 总体而言,数字乡村和智慧农业的建设,不仅能够提升农业生产效率和管理水平,还能够促进农村地区的社会经济发展,实现城乡融合发展,是推动中国农业现代化的重要途径。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值