【ZooKeeper】第二章 JavaAPI 操作

news2024/9/26 1:28:00

【ZooKeeper】第二章 JavaAPI 操作

文章目录

  • 【ZooKeeper】第二章 JavaAPI 操作
  • 一、Curator 简介
  • 二、Curator API
    • 1.建立连接
    • 2.创建节点
    • 3.查询节点
    • 4.修改节点
    • 5.删除节点
    • 6.Watch 事件监听
  • 三、分布式锁
  • 四、案例:12306售票

一、Curator 简介

  • Curator 是 Apache ZooKeeper 的 Java 客户端库
  • 常见的 ZooKeeper Java API:
    • 原生Java API
    • ZkClient
    • Curator
  • Curator 项目的目标是简化 Zookeeper 客户端的使用
  • Curator 最初是 Netflix 研发的,后来捐献给了 Apache 基金会
  • 官网:curator.apache.org

二、Curator API

1.建立连接

public void testConnect(){
    //1.第一种方式
    /*
     * @param connectString       list of servers to connect to     格式:ip:port,ip:port
     * @param sessionTimeoutMs    session timeout
     * @param connectionTimeoutMs connection timeout
     * @param retryPolicy         retry policy to use
     */
    String connectString = "172.20.10.2:2181";
    RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
    CuratorFramework client1 = CuratorFrameworkFactory.newClient(connectString, 60*1000, 15*1000, retryPolicy);
    //2.第二种方式
    CuratorFramework client2 = CuratorFrameworkFactory.builder()
            .connectString(connectString)
            .sessionTimeoutMs(60*1000)
            .connectionTimeoutMs(15*1000)
            .retryPolicy(retryPolicy)
            //操作目录时会自动拼接前缀 /sisyphus
            //.namespace("sisyphus")
            .build();
    //开启连接
    //client1.start();
    client2.start();
}

2.创建节点

public void testCreate() throws Exception {
    //1.基本创建
    //如果创建节点时没有指定数据,则默认将当前客户端的ip作为数据存储
    String path1 = client.create().forPath("/app1");
    System.out.println(path1);
    //2.创建带数据的节点
    String path2 = client.create().forPath("/app2", "hello".getBytes());
    System.out.println(path2);
    //3.设置节点的类型
    String path3 = client.create().withMode(CreateMode.EPHEMERAL).forPath("/app3");
    System.out.println(path3);
    //4.创建多级节点
    String path4 = client.create().creatingParentContainersIfNeeded().forPath("/app4/p1");
    System.out.println(path4);
}

3.查询节点

public void testGet() throws Exception {
    //testCreate();
    //1.查询数据:get
    byte[] data = client.getData().forPath("/app1");
    System.out.println(new String(data));
    //2.查询子节点:ls
    List<String> path = client.getChildren().forPath("/app4");
    System.out.println(path);
    //3.查询节点的状态信息:ls -s
    Stat stat = new Stat();
    client.getData().storingStatIn(stat).forPath("/app1");
    System.out.println(stat);
}

4.修改节点

public void testSet() throws Exception {
    //1.修改数据
    client.setData().forPath("/app1", "demo".getBytes());
    //2.根据版本修改
    Stat stat = new Stat();
    client.getData().storingStatIn(stat).forPath("/app1");
    int version = stat.getVersion();
    client.setData().withVersion(version).forPath("/app1", "demo".getBytes());
}

5.删除节点

public void testDelete() throws Exception{
    //1.删除单个节点
    client.delete().forPath("/app1");
    //2.删除带有子节点的节点
    client.delete().deletingChildrenIfNeeded().forPath("/app4");
    //3.必须成功的删除,会在会话有效期内不断重试直至成功
    client.delete().guaranteed().forPath("/app2");
    //4.回调
    client.delete().guaranteed().inBackground(new BackgroundCallback() {
        @Override
        public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
            System.out.println("我被删除了");
            System.out.println(event);
        }
    }).forPath("/app2");
}

6.Watch 事件监听

  • ZooKeeper 允许用户在指定节点上注册一些 Watcher,并且在一些特定事件触发的时候,ZooKeeper 服务端会将事件通知到感兴趣的客户端上,该机制是 ZooKeeper 实现分布式协调服务的重要特性
  • ZooKeeper 中引入了 Watcher 机制实现了发布/订阅功能,能够让多个订阅者同时监听某一个对象,当一个对象自身状态变化时,会通知所有订阅者
  • ZooKeeper 原生支持通过注册 Watcher 来进行事件监听,但是其使用并不是特别方便,需要开发人员反复注册 Watcher,比较繁琐
  • Curator 引入了 Cache 来实现对 ZooKeeper 服务端事件的监听
  • ZooKeeper 提供了三种 Watcher
    • NodeCache:只是监听某一个特定的节点
    • PathChildrenCache:监控一个 ZNode 的子节点
    • TreeCache:可以监控整个树上的所有节点,类似于 PathChildrenCache 和 NodeCache 的组合
public void testNodeCache() throws Exception {
    //1.创建NodeCache对象
    final NodeCache nodeCache = new NodeCache(client, "/app1");
    //2.注册监听
    nodeCache.getListenable().addListener(new NodeCacheListener() {
        @Override
        public void nodeChanged() throws Exception {
            System.out.println("节点变化了");
            //获取修改后的数据
            byte[] data = nodeCache.getCurrentData().getData();
            System.out.println(Arrays.toString(data));
        }
    });
    //3.开启监听,如果设置为true,则开启监听时加载缓存数据
    nodeCache.start(true);

    TimeUnit.SECONDS.sleep(60);
}

@Test
public void testPathChildrenCache() throws Exception{
    //1.创建监听对象
    PathChildrenCache pathChildrenCache = new PathChildrenCache(client, "/app2", true);
    //2.绑定监听器
    pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
        @Override
        public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
            System.out.println("子节点变化了");
            System.out.println(pathChildrenCacheEvent);
            //监听子节点的数据变更,并且拿到变更后的数据
            //获取类型
            PathChildrenCacheEvent.Type type = pathChildrenCacheEvent.getType();
            //判断类型是否是CHILD_UPDATED
            if(type.equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){
                System.out.println("数据变更!");
                byte[] data = pathChildrenCacheEvent.getData().getData();
                System.out.println(Arrays.toString(data));
            }
        }
    });
    //3.开启监听
    pathChildrenCache.start();

    TimeUnit.SECONDS.sleep(120);
}

三、分布式锁

  • 在我们进行单机应用开发时涉及并发同步的时候,我们往往采用 synchronized 或者 Lock 的方式来解决多线程间的代码同步问题,这时多线程的运行都是在同一个 JVM 之下,没有任何问题
  • 但当我们的应用是分布式集群工作的情况下,属于多 JVM 下的工作环境,跨 JVM 之间已经无法通过多线程的锁解决同步问题
  • 那么就需要一种更高级的锁机制,来处理这种跨机器的进程之间的数据同步问题——这就是分布式锁

ZooKeeper 分布式锁原理

  • 核心思想:当客户端要获取锁,则创建节点,使用完锁,删除该节点
    • 客户端获取锁时,在 lock 节点下创建临时(防止某个集群节点宕机无法释放锁)顺序节点
    • 然后获取 lock 下面的所有子节点,客户端获取到所有的子节点后,如果发现自己创建的子节点序号最小,那么就认为该客户端获取到了锁。使用完锁后,将该节点删除
    • 如果发现自己创建的节点并非 lock 所有子节点中最小的,说明自己还没有获取到锁,此时客户端需要找到比自己小的那个节点,同时对其注册事件监听器,监听删除事件
    • 如果发现比自己小的那个节点被删除,则客户端的 Watcher 会收到相应通知,此时再次判断自己创建的节点是否是 lock 子节点中序号最小的,如果是则获取到了锁,如果不是则重复以上步骤继续获取到比自己小的一个节点并注册监听

在这里插入图片描述
在 Curator 中有五种锁方案

  • InterProcessSemaphoreMutex:分布式排他锁(非可重入锁)
  • InterProcessMutex:分布式可重入排他锁
  • InterProcessReadWriteLock:分布式读写锁
  • InterProcessMultiLock:将多个锁作为单个实体管理的容器
  • InterProcessSemaphoreV2:共享信号量

四、案例:12306售票

在这里插入图片描述

模拟 12306 的数据库和被调用的减库存方法

package com.sisyphus.curator;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;

import java.util.concurrent.TimeUnit;

public class Ticket12306 implements Runnable{

    private int tickets = 10;       //数据库的票数

    private InterProcessMutex lock;

    public Ticket12306() {
        String connectString = "172.20.10.2:2181";
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString(connectString)
                .sessionTimeoutMs(60*1000)
                .connectionTimeoutMs(15*1000)
                .retryPolicy(retryPolicy)
                //操作目录时会自动拼接前缀 /sisyphus
                .namespace("sisyphus")
                .build();
        client.start();
        lock = new InterProcessMutex(client, "/lock");
    }

    @Override
    public void run() {
        while(true){
            //加锁
            try {
                lock.acquire(3, TimeUnit.SECONDS);
                if(tickets > 0){
                    System.out.println(Thread.currentThread() + ":" + tickets);
                    tickets--;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                //释放锁
                try{
                    lock.release();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }
}

用多个线程模拟 12306 多个服务器之间的锁竞争

package com.sisyphus.curator;

public class LockTest {
    public static void main(String[] args) {
        Ticket12306 ticket12306 = new Ticket12306();
        //创建客户端
        Thread t1 = new Thread(ticket12306, "携程");
        Thread t2 = new Thread(ticket12306, "飞猪");

        t1.start();
        t2.start();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/140177.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【云原生进阶之容器】第二章Controller Manager原理2.3节--Reflector分析

1 Reflector组件 1.1 背景 Reflector 是保证 Informer 可靠性的核心组件,在丢失事件,收到异常事件,处理事件失败等多种异常情况下需要考虑的细节很多。单独的listwatcher缺少重新连接和重新同步机制,有可能出现数据不一致问题。其对事件响应是同步的,如果执行复杂的操作会…

把财务分析明白的BI软件有哪些?

有财务分析这一个地狱级的在&#xff0c;什么销售、采购、库存都是渣渣。在财务分析中&#xff0c;指标运算组合可以有多样化的改变&#xff0c;资金来来回回能把人绕晕&#xff0c;一个极不起眼的疏忽都可能导致所有工作推到重来的可怕后果。即使是在擅长做大数据智能可视化分…

MySQL基础命令

MySQL基础命令 创建数据库 Show databases;查看 选择数据库 Use test; 在test数据库中创建表 create table t_stu( id int, name varchar(20) ); 查看表信息 desc t_stu&#xff1b; 添加字段 alter table t_stu add age int; 字段age成功添加 修改字段 alter tab…

springBoot使用rabbitmq并保证消息可靠性

一、理论说明 1.1、数据的丢失问题&#xff0c;可能出现在生产者、MQ、消费者中 1、如下图 1.2、生产者弄丢了数据 1、生产者将数据发送到 RabbitMQ 的时候&#xff0c;可能数据就在半路给搞丢了&#xff0c;因为网络问题啥的&#xff0c;都有可能。此时可以选择用RabbitM…

VS2019打包程序变成带运行环境的安装包

背景 给外行客户写程序的时候&#xff0c;为了避免客户麻烦&#xff0c;我们在写完程序之后&#xff0c;需要把运行环境也打包进安装包中&#xff0c;这样客户就可以一键安装使用。给客户减少麻烦的同时&#xff0c;无疑让我们也有了更多的好评。 步骤 1.写好我们要打包的程…

推荐16个前端必备的实用工具与网站

1. GitHub Desktop 对于新手来说&#xff0c;要记住那么多git命令可能有点困难&#xff0c;建议新手用git可视化工具&#xff0c;会方便很多 2. 图片在线压缩 tinypng 是一个完全免费并且高压缩率的在线压缩图片网站&#xff0c;一般能满足日常大部分压缩图片的需求&#x…

Visual Studio 2022最全安装教程(+背景图设置),一步步教会你如何安装并运行

目录visual studio 2022最全安装教程一、官网下载二、安装启动三、项目测试四、背景图设置 一、官网下载1.点击蓝色链接—->Visual Studio官网&#xff0c;进入之后是这个界面&#xff0c;选择社区版Community下载&#xff08;社区版Community是对个人免费的&#xff0c;一共…

磨金石教育科技技能干货分享|顶级黑白照片长啥样?看后令人震撼

黑白摄影往往在于一些老旧照片中见到&#xff0c;平常的摄影作品往往会强调一些色彩。黑白色调不是常用的色调。但在一些艺术摄影或者创意摄影中&#xff0c;黑白摄影依然是摄影师常用的一种风格。黑白色调往往能够给人一种肃穆、压抑的感觉。那么今天我们就通过一些作品&#…

(一)redis之Nosql数据库简介

一、技术发展 解决功能性的问题&#xff1a;Java、Jsp、RDBMS、Tomcat、HTML、Linux、JDBC、SVN 解决扩展性的问题&#xff1a;Struts、Spring、SpringMVC、Hibernate、Mybatis 解决性能的问题&#xff1a;NoSQL、Java线程、Hadoop、Nginx、MQ、ElasticSearch 1、Web1.0 W…

VMware 基本设置

VMware 基本设置 文章目录VMware 基本设置摘要全局优化内存优先级更新反馈虚拟机系统优化尽可能多的分配资源去掉多余的组件开启3D图形加速和增加显存大小高级设置优化显示关键字&#xff1a; 显示、 内存、 优化、 命令栏、 虚拟机摘要 做Qt开发 久了&#xff0c;跨平台应该…

【BSP视频教程】BSP视频教程第25期:CAN/CANFD/CANopen专题,CAN知识点干货分享, 收发执行过程和错误帧处理(2023-01-03)

视频教程汇总帖&#xff1a;【学以致用&#xff0c;授人以渔】2023视频教程汇总&#xff0c;DSP第10期&#xff0c;ThreadX第5期&#xff0c;BSP驱动第25期&#xff0c;USB实战第5期&#xff0c;GUI实战第3期&#xff08;2023-01-03&#xff09; - STM32F429 - 硬汉嵌入式论坛 …

梦之光芒Monyer (全关解析)

目录 前言: 第0关 描述: 过程: 第1关 描述: 过程: 第2关 描述: 过程: 第3关 描述: 过程: 第4关 描述: 过程: 第5关 描述: 过程: 第6关 描述: 过程: 第7关 描述: 过程: 第8关 描述: 过程: 第9关 描述: 过程: 第10关 描述: 过程: 第11关 描…

spring mvc文档阅读笔记——01

目录标题一、文档地址二、文档目录索引简介&#xff08;一&#xff09;Spring Web MVC1. 常用注解的使用2. 过滤器3. WebMvcConfigurer&#xff08;二&#xff09;RestTemplate&#xff08;三&#xff09;WebSocket三、Spring Web MVC&#xff08;一&#xff09;ControllerRest…

CSS知识点精学3-CSS浮动

目录 结构伪类选择器 伪元素 标准流 浮动 清除浮动 结构伪类选择器 目标&#xff1a;能够使用结构伪类选择器在HTML中定位元素 1.作用&#xff1a;工具元素在HTML中的结构关系查找元素 2.优势&#xff1a;减少对于HTML中类的依赖&#xff0c;有利于保持代码整洁 3.场景…

5G NR标准 第10章 物理层控制信令

为了支持下行链路和上行链路传输信道的传输&#xff0c;需要某些相关联的控制信令。这种控制信令通常被称为L1/L2控制信令&#xff0c;表示相应的信息部分来自物理层&#xff08;层1&#xff09;并且部分来自MAC&#xff08;层2&#xff09;。在本章中&#xff0c;将描述下行链…

一套WPF+EF+SQLServer 会员卡管理系统源码

今天分享的是一套WPFEFSQLServer 会员卡管理系统源码&#xff0c;界面使用Panuon.WPF.UI&#xff0c;图表工具使用LiveCharts.Wpf&#xff0c;麻雀虽小五脏俱全&#xff0c;该源码作Panuon.WPF.UI的示例入门较为合适&#xff0c;包含了常规控件的附加属性及官方文档中没有提及的…

前端性能的计算方式与优化方案

文章目录1.Navigation Timing1.1 什么是Navigation Timing1.2 Navigation Timing具体说明1.2.1 缓存处理阶段1.2.2 网络请求阶段1.2.3 dom渲染阶段1.3 使用1.3.1 如何查看1.3.2 项目中的使用2.Core Web Vitals - CWV 网页性能三大指标2.1 Largest Contenful Paint(LCP)扩展&…

C语言_自定义数据类型

目录 1.自定义数据类型_结构体 1.1 结构体类型的声明 1.1.1 匿名结构体 1.2 结构体的自引用 1.2.1 Typedef结构体重命名&#xff1a; 1.3 结构体变量的定义和初始化 1.4 结构体内存对齐 1.4.1 结构体的对齐规则 1.4.2 为什么存在内存对齐&#xff1f; 1.4.3 设置默认…

【闲聊杂谈】一篇给你讲清楚JVM调优的本质

1、什么是JVM JVM的定义 在说JVM之前&#xff0c;首先要知道什么是JVM。JVM是JavaVirtualMachine&#xff08;Java虚拟机&#xff09;的缩写&#xff0c;JVM是一种用于计算设备的规范&#xff0c;它是一个虚构出来的计算机&#xff0c;是通过在实际的计算机上仿真模拟各种计算…

SpringBoot整合Quartz实现动态定时任务(三十四)

二八佳人体似酥&#xff0c;腰间仗剑斩愚夫。虽然不见人头落&#xff0c;暗里教君骨髓枯。 上一章简单介绍了 SpringBoot定时任务(三十三) ,如果没有看过,请观看上一章 关于 Quartz&#xff0c; 可以看老蝴蝶之前的文章: https://blog.csdn.net/yjltx1234csdn/category_995397…