【ZooKeeper学习笔记】

1. ZooKeeper基本概念

Zookeeper官网:https://zookeeper.apache.org/index.html

  • Zookeeper是Apache Hadoop项目中的一个子项目,是一个树形目录服务
  • Zookeeper翻译过来就是动物园管理员,用来管理Hadoop(大象)、Hive(蜜蜂)、Pig(小猪)的管理员,简称zk
  • Zookeeper的本质是一个分布式的、开源的、提供分布式应用程序协调服务的组件
  • Zookeeper提供的主要功能有:
    • 配置管理
    • 分布式锁
    • 集群管理

2. ZooKeeper常用命令

2.1 ZooKeeper数据模型

在正式介绍Zookeeper的常用命令之前,我们先来了解一下Zookeeper的相关数据模型:

  • Zookeeper的是一个树形目录服务,其数据模型与unix文件系统目录树类似,是一个层次化的结构
  • 这里面的每一个节点都被称为ZNode,每个节点上都会保存自己的数据以及元数据信息
  • 节点也可以拥有子节点,同时允许少量数据(1MB)存储在该节点之下
  • 节点类型大致可以分为如下四类:
    • PERSISTENT:持久化节点
    • EPHEMERAL:临时节点 -e
    • PERSISTENT_SEQUENTIAL:持久化顺序节点 -s
    • EPHEMERAL_SEQUENTIAL:临时顺序节点 -e -s

2.2 ZooKeeper常用命令

Zookeeper是一个常见的客户端-服务器模型,我们可以使用命令行或者JavaAPI的方式充当客户端进行访问,其架构如下图所示:

  • 服务端命令:
  1. ./zkServer.sh start启动zookeeper服务

image.png

  1. ./zkServer.sh status查看zookeeper服务运行状态

image.png

  1. ./zkServer.sh restart重启zookeeper服务

image.png

  1. ./zkServer.sh stop关闭zookeeper服务

image.png

  • 客户端命令:
  1. ./zkCli.sh -server ip:port连接指定的zookeeper服务(如连接本地可忽略选项直接使用./zkCli.sh)

image.png

  1. quit退出客户端交互界面

image.png

  1. help查看命令帮助

image.png

  1. ls 目录查看指定目录下的znode节点

image.png

  1. ls -s 目录查看节点详细信息

image.png

  1. create znode [value]创建znode节点(可以携带data)

image.png

  1. create znode -e [value]创建临时节点(会话结束后消失)
  2. create znode -s [value]创建顺序节点

image.png

  1. get znode查看节点携带数据

image.png

  1. set znode value设置节点数据

image.png

  1. delete znode删除指定的znode节点(必须为空)

image.png

  1. deleteall znode删除指定的znode节点及其子节点

image.png

2.3 ZooKeeper的JavaAPI操作

2.3.1 Curator介绍

Curator:是一个Zookeeper的Java客户端库

  • 常见的Zookeeper Java客户端有如下几种:
    1. 原生JavaAPI
    2. ZkClient
    3. Curator
  • Curator的目标就是简化Zookeeper客户端的使用
  • Curator项目最初有Netflix公司研发,后来捐给了Apache基金会,成为顶级项目

Curator官网:http://curator.apache.org/

2.3.2 Curator API操作
2.3.2.1 建立连接

我们可以使用CuratorFrameworkFactory静态工厂类进行创建,可以通过如下两种方式配置:

  1. 使用newClient()方法
  2. 使用build()方法

下面我们就给出对应两种代码的实现方式:
newClient:

/**
 * ZooKeeper测试类
 */
public class ZooKeeperTest {

    private CuratorFramework client = null;

    @Before
    public void initByNewClient() {
        CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181",
                3000,
                3000,
                new ExponentialBackoffRetry(3000, 1));
        this.client = client;
        this.client.start();
    }
}

build:

/**
 * ZooKeeper测试类
 */
public class ZooKeeperTest {

    private CuratorFramework client = null;

    @Before
    public void init() {
        CuratorFramework client = CuratorFrameworkFactory
                .builder()
                .connectString("127.0.0.1:2181")
                .sessionTimeoutMs(3000)
                .connectionTimeoutMs(3000)
                .retryPolicy(new ExponentialBackoffRetry(3000, 1))
                .namespace("")
                .build();
        client.start();
        this.client = client;
    }
}

其中各个配置项含义如下:

  • connectString:连接字符串,配置服务器地址,格式为ip:port
  • sessionTimeoutMs:会话超时时间
  • connectionTimeoutMs:连接超时时间
  • retryPolicy:重试策略
  • namespace:设置根目录位置
2.3.2.2 创建节点

创建节点有如下常见的四种方式:
Case1:创建节点(不携带数据)

@Test
public void testCreate1() throws Exception {
    String path = client.create().forPath("/app1");
    System.out.println(path);
}

Case2:创建节点(携带数据)

@Test
public void testCreate2() throws Exception {
    String path = client.create().forPath("/app2", "curator java api".getBytes());
    System.out.println(path);
}

Case3:创建多级节点

@Test
public void testCreate4() throws Exception {
    client.create().creatingParentsIfNeeded().forPath("/test/test1/test2");
}

Case4:创建节点并指定类型

@Test
public void testCreate3() throws Exception {
    client.create().withMode(CreateMode.EPHEMERAL).forPath("/app3");
    client.create().withMode(CreateMode.PERSISTENT).forPath("/app4");
    client.create().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath("/app5");
    client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/app6");
}
2.3.2.3 删除节点

删除节点有如下常见的两种方式:
Case1:删除节点(不含子节点)

@Test
public void testDelete() throws Exception {
    client.delete().forPath("/app1");
}

Case2:删除节点(递归删除子节点)

@Test
public void testDeleteAll() throws Exception {
    client.delete().deletingChildrenIfNeeded().forPath("/test");
}
2.3.2.4 查询节点

查询节点有如下常见的三种方式:
Case1:查询子节点信息

@Test
public void testGetChildren() throws Exception {
    List<String> childrenList = client.getChildren().forPath("/");
    System.out.println(childrenList);
}

Case2:查询节点数据

@Test
public void testGetData() throws Exception {
    byte[] bytes = client.getData().forPath("/app2");
    System.out.println("data: " + new String(bytes));
}

Case3:查询节点详细信息

@Test
public void testGetData3() throws Exception {
    Stat stat = new Stat();
    client.getData().storingStatIn(stat).forPath("/app2");
    System.out.println(stat);
}
2.3.2.5 修改节点

修改节点有如下常见的两种方式:
Case1:修改节点数据

@Test
public void testSetData() throws Exception {
    Stat stat = client.setData().forPath("/app1", "some data".getBytes());
    System.out.println(stat);
}

Case2:修改节点数据(带有版本号)

@Test
public void testSetData2() throws Exception {
    Stat stat = new Stat();
    client.getData().storingStatIn(stat).forPath("/app2");
    int version = stat.getVersion();
    System.out.println(version);
    client.setData().withVersion(version).forPath("/app2", "set with version".getBytes());
}

3. ZooKeeper的事件监听机制

Watcher事件监听机制:

  • ZooKeeper允许用户在指定节点上注册一些Watcher,当一些特定事件发生时,ZooKeeper就会将事件通知给对其感兴趣的客户端,这是ZooKeeper提供分布式协调服务的重要特性
  • ZooKeeper引入了Watcher机制来实现发布 / 订阅功能,能够让多个订阅者同时监听某一个对象,当一个对象状态发生变化时就会通知所有订阅者
  • ZooKeeper提供原生Watcher的方式,但是比较麻烦,因此Curator使用Cache数据结构进行了优化实现监听机制
  • Curator提供了如下三种Cache:
    1. NodeCache:只监听某一个指定的节点变化
    2. PathChildrenCache:监控一个节点的所有子节点
    3. TreeCache:监控整个树上的节点,类似于前两者的组合

3.1 Node Cache

代码实现:

@Test
public void testCuratorCache() throws Exception {
    NodeCache cache = new NodeCache(client, "/app1");
    cache.getListenable().addListener(new NodeCacheListener() {
        @Override
        public void nodeChanged() throws Exception {
            System.out.println("监听到节点变化...");
        }
    });
    cache.start();
    while (true) {

    }
}

3.2 PathChildren Cache

代码实现:

@Test
public void testPathChildrenCache() throws Exception {
    PathChildrenCache cache = new PathChildrenCache(client, "/app1", true);
    cache.getListenable().addListener(new PathChildrenCacheListener() {
        @Override
        public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
            System.out.println("监听到子节点变化...");
            PathChildrenCacheEvent.Type type = pathChildrenCacheEvent.getType();
            if (type.equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)) {
                System.out.println("监听到子节点数据变化...");
                System.out.println("更新后数据: " + pathChildrenCacheEvent.getData().getData());
            }
        }
    });
    cache.start();
    while (true) {

    }
}

3.3 Tree Cache

代码实现:

 @Test
    public void testTreeCache() throws Exception {
        TreeCache cache = new TreeCache(client, "/app1");
        cache.getListenable().addListener(new TreeCacheListener() {
            @Override
            public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
                System.out.println("监听到节点发生变化...");
                System.out.println(treeCacheEvent);
            }
        });
        cache.start();
        while (true) {

        }
    }

4. ZooKeeper分布式锁

4.1 ZooKeeper分布式锁原理

  • 核心思想:当用户获取到锁时就创建节点,使用完锁就删除节点
  1. 每当一个用户想要获取锁时就在/lock节点下创建一个 **临时顺序 **节点
  2. 然后获取/lock节点下的全部子节点,如果发现当前节点编号是最小的,则该节点对应的客户端获取到锁,使用完锁后,删除该节点
  3. 如果发现节点编号不是最小的,则对前一个比自己小的编号节点,并注册事件监听器,监听删除事件
  4. 如果后续发现比自己小的节点被删除,则客户端会接收到来自ZooKeeper的通知,然后再次判断所对应节点编号是否是最小的,重复上述步骤

注意:这里创建临时节点是因为防止获取到锁的客户端宕机了,进而导致锁永远不会被删的情况;这是创建顺序节点是方便编号的排序

Cutator提供了下面五种分布式锁的方式:

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

4.2 分布式锁实战(模拟12306抢票)

代码如下:

package org.example;

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 ZooKeeperLockTest {

    private static int tickets = 10; // 票数

    public static void main(String[] args) {
        // 建立连接
        CuratorFramework client = CuratorFrameworkFactory
                .builder()
                .connectString("127.0.0.1:2181")
                .sessionTimeoutMs(3000)
                .connectionTimeoutMs(3000)
                .retryPolicy(new ExponentialBackoffRetry(3000, 1))
                .namespace("")
                .build();
        client.start();
        // 获取分布式锁
        InterProcessMutex lock = new InterProcessMutex(client, "/lock");
        Thread t1 = new Thread(() -> {
            while (true) {
                try {
                    boolean hasLock = lock.acquire(3, TimeUnit.SECONDS);
                    if (hasLock && tickets > 0) {
                        // 不断抢票
                        System.out.println("线程" + Thread.currentThread().getName() + "抢到了当前第" + tickets + "张票");
                        tickets--;
                        if (tickets <= 0) {
                            break;
                        }
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    try {
                        lock.release();
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }, "携程");

        Thread t2 = new Thread(() -> {
            while (true) {
                try {
                    boolean hasLock = lock.acquire(3, TimeUnit.SECONDS);
                    if (hasLock && tickets > 0) {
                        // 不断抢票
                        System.out.println("线程" + Thread.currentThread().getName() + "抢到了当前第" + tickets + "张票");
                        tickets--;
                        if (tickets <= 0) {
                            break;
                        }
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    try {
                        lock.release();
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }, "飞猪");
        t1.start();
        t2.start();
    }
}

5. ZooKeeper集群管理

Leader选举过程:

  • ServerId:服务器ID

比如有三台服务器,编号分别是1,2,3。则编号越大在选择算法中的权重就越大

  • Zxid:数据ID

服务器中存放的数据ID越大,值越大说明更新的越频繁,则在选择算法中的权重就越大

  • 在Leader选举的过程中如果某台ZooKeeper超过了半数选票,则直接当选为Leader

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据恢复篇:适用于 Android 的恢复工具

正在摆弄 Android 设备。突然&#xff0c;您意外删除了一张或多张图片。不用担心&#xff0c;您总能找到一款价格实惠的照片恢复应用。这款先进的软件可帮助 Android 用户从硬盘、安全数字 (SD) 或存储卡以及数码相机中恢复已删除的图片。 Android 上文件被删除的主要原因 在获…

昇思学习打卡-13-LLM原理与实践/解码原理--以MindNLP为例

文章目录 搜索方法集束搜索(beam search)贪心搜索(greedy search) 采样池处理结果 一个文本序列的概率分布可以分解为每个词基于其上文的条件概率的乘积 搜索方法 集束搜索(beam search) Beam search通过在每个时间步保留最可能的 num_beams 个词&#xff0c;并从中最终选择出…

C++·多态

1. 多态的概念 多态通俗讲就是多种形态&#xff0c;就是指去完成某个行为&#xff0c;当不同对象去做时会产生不同的结果或状态。 比如买火车票这个行为&#xff0c;同样是买票的行为&#xff0c;普通成年人买到全价票&#xff0c;学生买到半价票&#xff0c;军人优先买票。这个…

NFT如何解决音乐版权的问题

音乐版权问题一直困扰着音乐产业。传统的音乐版权管理模式存在以下问题。需要注意的是&#xff0c;NFT在音乐版权领域仍处于早期发展阶段&#xff0c;存在一些需要解决的问题&#xff0c;例如技术标准不统一、应用场景有限、法律法规不明朗等。但随着技术的进步和市场的完善&am…

可重入锁深入学习(有码)

【摘要】 ​今天&#xff0c;梳理下java中的常用锁&#xff0c;但在搞清楚这些锁之前&#xff0c;先理解下 “临界区”。临界区在同步的程序设计中&#xff0c;临界区段活称为关键区块&#xff0c;指的是一个访问共享资源&#xff08;例如&#xff1a;共享设备或是共享存储器&a…

路径规划 | 飞蛾扑火算法求解二维栅格路径规划(Matlab)

目录 效果一览基本介绍程序设计参考文献 效果一览 基本介绍 路径规划 | 飞蛾扑火算法求解二维栅格路径规划&#xff08;Matlab&#xff09;。 飞蛾扑火算法&#xff08;Firefly Algorithm&#xff09;是一种基于自然界萤火虫行为的优化算法&#xff0c;在路径规划问题中也可以应…

Nginx入门到精通三(反向代理1)

下面内容整理自bilibili-尚硅谷-Nginx青铜到王者视频教程 Nginx相关文章 Nginx入门到精通一&#xff08;基本概念介绍&#xff09;-CSDN博客 Nginx入门到精通二&#xff08;安装配置&#xff09;-CSDN博客 Nginx入门到精通三&#xff08;Nginx实例1&#xff1a;反向代理&a…

子进程继承父进程文件描述符导致父进程打开设备文件失败

开发过程中有时会遇到需要在程序中执行三方程序或者shell脚本&#xff0c;一般会通过system(), popen(), exec簇来完成该功能。我们知道以上方法会通过fork创建子进程后在子进程中执行相应指令。如图1为某个示例流程&#xff0c;具体的程序执行流程如图2所示&#xff0c;线程my…

使用Python和MediaPipe实现手势控制音量(Win/Mac)

1. 依赖库介绍 OpenCV OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库。它包含了数百个计算机视觉算法。 MediaPipe MediaPipe是一个跨平台的机器学习解决方案库&#xff0c;可以用于实时人类姿势估计、手势识…

godis源码分析——database存储核心1

前言 redis的核心是数据的快速存储&#xff0c;下面就来分析一下godis的底层存储是如何实现&#xff0c;先分析单机服务。 此文采用抓大放小原则&#xff0c;先大的流程方向&#xff0c;再抓细节。 流程图 源码分析 现在以客户端连接&#xff0c;并发起set key val命令为例…

简单的SQL字符型注入

目录 注入类型 判断字段数 确定回显点 查找数据库名 查找数据库表名 查询字段名 获取想要的数据 以sqli-labs靶场上的简单SQL注入为例 注入类型 判断是数字类型还是字符类型 常见的闭合方式 ?id1、?id1"、?id1)、?id1")等&#xff0c;大多都是单引号…

微分方程的解法(Matlab)

微分方程分为刚性微分方程和非刚性微分方程&#xff0c;在数值解法中的表现和行为特性上存在显著差异。 刚性微分方程&#xff08;Stiffness Equation&#xff09;是指其数值分析的解只有在时间间隔很小时才会稳定&#xff0c;只要时间间隔略大&#xff0c;其解就会不稳定。这…

【BUG】Python3|COPY 指令合并 ts 文件为 mp4 文件时长不对(含三种可执行源代码和解决方法)

文章目录 前言源代码FFmpeg的安装1 下载2 安装 前言 参考&#xff1a; python 合并 ts 视频&#xff08;三种方法&#xff09;使用 FFmpeg 合并多个 ts 视频文件转为 mp4 格式 Windows 平台下&#xff0c;用 Python 合并 ts 文件为 mp4 文件常见的有三种方法&#xff1a; 调用…

项目范围管理-系统架构师(二十九)

1、&#xff08;重点&#xff09;软件设计包括了四个独立又相互联系的活动&#xff0c;高质量的&#xff08;&#xff09;将改善程序结构的模块划分&#xff0c;降低过程复杂度。 A程序设计 B数据设计 C算法设计 D过程设计 解析&#xff1a; 软件设计包含四个&#xff0c;…

博客前端项目学习day01

这里写自定义目录标题 登录创建项目配置环境变量&#xff0c;方便使用登录页面验证码登陆表单 在VScode上写前端&#xff0c;采用vue3。 登录 创建项目 检查node版本 node -v 创建一个新的项目 npm init vitelatest blog-front-admin 中间会弹出询问是否要安装包&#xff0c…

R语言安装devtools包失败过程总结

R语言安装devtools包时&#xff0c;遇到usethis包总是安装失败&#xff0c;现总结如下方法&#xff0c;亲测可有效 一、usethis包及cli包安装问题 首先&#xff0c;Install.packages("usethis")出现如下错误&#xff0c;定位到是这个cli包出现问题 载入需要的程辑包…

Mac和VirtualBox Ubuntu共享文件夹

1、VirtualBox中点击设置->共享文件夹 2、设置共享文件夹路径和名称&#xff08;重点来了&#xff1a;共享文件夹名称&#xff09; 3、保存设置后重启虚拟机&#xff0c;执行下面的命令 sudo mkdir /mnt/share sudo mount -t vboxsf share /mnt/share/ 注&#xff1a;shar…

.快速幂.

按位与&#xff08;Bitwise AND&#xff09;是一种二进制运算&#xff0c;它逐位对两个数的二进制表示进行运算。对于每一位&#xff0c;只有两个相应的位都为1时&#xff0c;结果位才为1&#xff1b;否则&#xff0c;结果位为0。如&#xff1a;十进制9 & 5转化为二进制&am…

基于lstm的股票Volume预测

LSTM&#xff08;Long Short-Term Memory&#xff09;神经网络模型是一种特殊的循环神经网络&#xff08;RNN&#xff09;&#xff0c;它在处理长期依赖关系方面表现出色&#xff0c;尤其适用于时间序列预测、自然语言处理&#xff08;NLP&#xff09;和语音识别等领域。以下是…

酒店管理系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;酒店管理员管理&#xff0c;房间类型管理&#xff0c;房间信息管理&#xff0c;订单信息管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;房间信息…