【ZooKeeper学习笔记】

news2024/11/15 10:09:39

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.coloradmin.cn/o/1925409.html

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

相关文章

浪潮信息F-OCC算法夺冠,自动驾驶感知技术再创新高

浪潮信息&#xff0c;作为行业领先的AI技术提供商&#xff0c;其AI团队在近期举办的全球权威CVPR 2024自动驾驶国际挑战赛(Autonomous Grand Challenge)中大放异彩&#xff0c;凭借“F-OCC”算法模型以48.9%的卓越成绩&#xff0c;一举夺得占据栅格和运动估计(Occupancy & …

前端Vue组件化实践:打造仿京东天猫商品属性选择器组件

在前端开发领域&#xff0c;随着业务需求的日益复杂和技术的不断进步&#xff0c;传统的整体式应用开发模式已逐渐显得捉襟见肘。面对日益庞大的系统&#xff0c;每次微小的功能修改或增加都可能导致整个逻辑结构的重构&#xff0c;形成牵一发而动全身的困境。为了解决这一问题…

基于Node.js将个人网站部署到ECS

基于Node.js将个人网站部署到云端ECS 一、如何购买ECS以及如何使用学生认证优惠&#xff1f;1.进入阿里云网站&#xff0c;进行学生认证2.购买学生优惠&#xff0c;免费试用一个月3.重置个人密码 二、服务器的配置以及与宝塔面板的链接1.个人电脑打开终端&#xff08;winR->…

探索性数据分析:使用Python与Pandas库实现数据洞察

探索性数据分析&#xff1a;使用Python与Pandas库实现数据洞察 引言 在当今数据驱动的时代&#xff0c;数据分析已成为决策制定、策略规划和业务优化的关键环节。无论是商业智能、金融分析还是市场研究&#xff0c;数据分析都扮演着至关重要的角色。Pandas库作为Python生态系统…

一文SpringCloud

Springcloud 什么是Springcloud&#xff1f; 官网&#xff1a;Spring Cloud Data Flow Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发&#xff0c;如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控…

Flat Ads:金融APP海外广告投放素材的优化指南

在当今全球化的数字营销环境中,金融APP的海外营销推广已成为众多金融机构与开发者最为关注的环节之一。面对不同地域、文化及用户习惯的挑战,如何优化广告素材,以吸引目标受众的注意并促成有效转化,成为了广告主们亟待解决的问题。 作为领先的全球化营销推广平台,Flat Ads凭借…

树莓派PICO使用INA226测量电流和总线电压(3)

上一篇文章我们讲了如何测试电流&#xff0c;但是INA226有一个非常典型的问题&#xff0c;那就是误差比较大&#xff0c;因为采样电阻非常小&#xff0c;我的开发板用的是100mΩ的采样电阻&#xff0c;在设定中我也用的是这个采样电阻值&#xff0c;但事实上&#xff0c;测试得…

文件内容查阅

cat concatenate files and print on the standard output Linux中一个最简单的且最常用的命令是cat命令。其功能是在终端设备上显示文件内容。 cat命令-n选项用于显示行号。 tac concatenate and print files in reverse tac命令的功能是用于反向显示文件内容&#xff0c;即…

【Qt 基础】绘图

画笔 QPen pen; pen.setWidth(3); // 线条宽度 pen.setColor(Qt::red);// 画笔颜色 pen.setStyle(Qt::DashLine);// 线条样式 pen.setCapStyle(Qt::RoundCap);// 线端样式 pen.setJoinStyle(Qt::BevelJoin);// 连接样式 painter.setPen(pen);线条 线端 连接 画刷 QBrush bru…

css设置弹性flex后,如果设置100vh高度不撑满的原因

问题 父元素设置height为100%&#xff0c;有两个子元素&#xff0c;第一个设置height:100vh&#xff0c;第二个设置flex:1&#xff0c;此时第一个高度无法撑满盒子 原因解决方式 当父元素设置display为flex,第一个div设置高度64px,剩一个div设置高度为flex&#xff1a;1,这时…

数据处理-Matplotlib 绘图展示

文章目录 1. Matplotlib 简介2. 安装3. Matplotlib Pyplot4. 绘制图表1. 折线图2. 散点图3. 柱状图4. 饼图5. 直方图 5. 中文显示 1. Matplotlib 简介 Matplotlib 是 Python 的绘图库&#xff0c;它能让使用者很轻松地将数据图形化&#xff0c;并且提供多样化的输出格式。 Ma…

Qt项目中添加自定义文件夹,进行整理归类

Qt项目中添加文件夹进行归类 1、在windows的工程目录下创建一个文件夹&#xff0c;如widgets 2、将.h 、.cpp、.ui文件拷贝到windows该文件夹widgets 3、在qt工程中&#xff0c;根目录右键&#xff0c;选择添加现有文件&#xff0c;批量选择 .h 、.cpp、.ui文件之后&#xf…

初识影刀:EXCEL根据部门筛选低值易耗品

第一次知道这个办公自动化的软件还是在招聘网站上&#xff0c;了解之后发现对于办公中重复性的工作还是挺有帮助的&#xff0c;特别是那些操作非EXCEL的重复性工作&#xff0c;当然用在EXCEL上更加方便&#xff0c;有些操作比写VBA便捷。 下面就是一个了解基本操作后&#xff…

开发总结 - H5/web C端评论区开发逻辑

1. 背景 平时做的系统都是偏公司业务的系统&#xff0c;这次开发了一个用户评论的功能&#xff0c;同时开发了web版和H5版本的&#xff0c;因为没有做过这种C端的常用的功能&#xff0c;所以记录一下此次的开发&#xff0c;从参考友商设计到独立思考业务之间的区别再到实际开发…

everything搜索不到任何文件-设置

版本&#xff1a; V1.4.1.1024 (x64) 问题&#xff1a;搜索不到任何文件 click:[工具]->[选项]->下图所示 将本地磁盘都选中包含

2024 辽宁省大学数学建模竞赛B 题 钢铁产品质量优化完整思路 代码 结果分享(仅供学习)

冷轧带钢是钢铁企业的高附加值产品,其产品质量稳定性对于钢铁企业的经济效益具有非常重要的影响。在实际生产中&#xff0c;冷连轧之后的带钢需要经过连续退火处理来消除因冷轧产生的内应力并提高其机械性能。连续退火的工艺流程如图1 所示&#xff0c;一般包括加热、保温、缓冷…

Datawhale AI 夏令营 Task1

记录第一次参加Kaggle上的比赛&#xff0c;通过一站式的教程&#xff0c;没有一点阻碍的跑通了baseline 夏令营方向的选择 我选择的夏令营是关于CV方向的&#xff0c;因为本身对于cv方向比较感兴趣&#xff0c;而且这次夏令营的方式我很喜欢&#xff0c;通过比赛来促进学习&a…

板级调试小助手(5)基于Python访问千帆大模型

一、前言 千帆大模型是百度提供的可以使用API接口调用GPT模型&#xff0c;使用Python调用其实是很简单的&#xff1a;去千帆大模型申请账号->使用python调用API即可&#xff0c;具体可以参考这位大佬的博客&#xff0c;这里就不赘述了。 【教程】如何用Python调用百度的千帆…

基于Java+SpringMvc+Vue技术的药品进销存仓库管理系统设计与实现系统(源码+LW+部署讲解)

注&#xff1a;每个学校每个老师对论文的格式要求不一样&#xff0c;故本论文只供参考&#xff0c;本论文页数达到60页以上&#xff0c;字数在6000及以上。 基于JavaSpringMvcVue技术的在线学习交流平台设计与实现 目录 第一章 绪论 1.1 研究背景 1.2 研究现状 1.3 研究内容…

数据结构和算法(0-1)----递归

定义​ 递归是一种在程序设计中常用的技术&#xff0c;它允许一个函数调用自身来解决问题。递归通常用于解决那些可以被分解为相似的子问题的问题&#xff0c;这些问题的解决方式具有自相似性。在数据结构和算法中&#xff0c;递归是一种重要的解决问题的方法&#xff0c;尤其是…