【Zookeeper】学习笔记(二)

news2024/10/6 16:28:30

Zookeeper学习笔记

  • 四、客户端命令
    • 4.1、新增节点
    • 4.2、查询节点信息
    • 4.3、节点类型
    • 4.4、更新节点
    • 4.5、删除节点
    • 4.6、监听器
  • 五、SpringBOOT整合Zookeeper
  • 六、写数据流程
    • 6.1、写流程之写入请求直接发送给Leader节点
    • 6.2、写流程之写入请求发送给follower节点
  • 七、服务器动态上下线监听
    • 7.1、案例
  • 八、分布式锁
    • 8.1、分析
    • 8.1、案例
  • 九、其他
    • 9.1、生产集群安装多少k合适

四、客户端命令

在bin目录下 集群客户端启动命令

./zkCli.sh -server 192.168.3.34:2181

4.1、新增节点

命令格式:

# -s 为有序节点, -e 为临时节点
create [-s] [-e] path data

创建持久化节点并写入数据:

# 创建 hadoop节点,内容为123456
create /hadoop "123456"
# 读取节点内容
get /hadoop

创建持久化有序节点。此时创建出来的节点名称为:指定的节点名+自增序号:

#创建出来的节点名称为:指定的节点名+自增序号:# 此时创建出来的节点名称为/a0000000001
create -s /a "a"

# 再创建/b时,节点名称为/b0000000002
create -s /b "b"

创建临时节点:

create -e /tmp "tmp"

# 创建完之后,通过get /tmp可以查到
get /tmp

# 使用quit退出当前会话
quit

# 重新打开zkCli,get /tmp 找不到该节点
get /tmp

创建临时有序节点,可用于分布式锁:

# 创建的临时节点:/t0000000004
create -s -e /t "tt"

4.2、查询节点信息

节点数据信息

ls -s /

节点属性说明:

  • cZxid:数据节点创建时的事务ID
  • ctime:数据节点创建时的时间
  • mZxid:数据节点最后一次更新时的事务ID
  • pZxid:数据节点最后一次更新时的时间
  • cversion:子节点的更改次数
  • dataVersion:节点数据的更改次数
  • aclVersion:节点的ACL的更改次数
  • ephemeralOwner:如果节点是临时节点,则表示创建该节点的会话sessionID。如果节点是持久节点,则该属性值为0
  • dataLength:数据内容的长度
    numChildren:数据节点当前的子节点个数

4.3、节点类型

持久(Persistent):客户端和服务器端断开连接后,创建的节点不删除
短暂(Ephemeral):客户端和服务器端断开连接后,创建的节点自己删除

  1. 持久化目录节点
    客户端与Zookeeper断开连接后,该节点依旧存在
  2. 持久化顺序编号目录节点
    客户端与Zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号由父节点维护
  3. 临时目录节点
    客户端与Zookeeper断开连接后,该节点被删除
  4. 临时顺序编号目录节点
    客户端与Zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号。让天下漫有难学的技

4.4、更新节点

set /hadoop "1234"

4.5、删除节点

delete /hadoop

4.6、监听器

1、监听原理详解

  1. 首先要有一个main()线程
  2. 在main线程中创建Zookeeper客户端,这时就会创建两个线程,一个负责网络连接通信(connet) ,一个负责监听(listener) 。
  3. 通过connect线程将注册的监听事件发送给Zookeeper。
  4. 在Zookeeper的注册监听器列表中将注册的监听事件添加到列表中。
  5. Zookeeper监听到有数据或路径变化,就会将这个消息发送给listener线程。
  6. listener线程内部调用了process()方法。

在这里插入图片描述

监听节点数据的变化

get path [watch]
# 注册一次,只能监听一次。想再次监听,需要再次注册。

监听子节点增减的变化

ls path [watch]

五、SpringBOOT整合Zookeeper

SpringBOOT整合Zookeeper

六、写数据流程

6.1、写流程之写入请求直接发送给Leader节点

在这里插入图片描述

  1. 客户端想服务器leader写入数据
  2. leader向slave1写入
  3. slave1写完向leader发送ack表示自己写入完成
  4. 只要超过半数,就可以应答了 leader向客户端发送ack
  5. leader向slave2写入
  6. slave2写完向leader发送ack表示自己写入完成

6.2、写流程之写入请求发送给follower节点

在这里插入图片描述

  1. 客户端想服务器slave1写入数据
  2. slave1没有写入权限、将数据转发给leader
  3. leader写入后再向slave1写入
  4. slave1写完向leader发送ack表示自己写入完成
  5. 只要超过半数,就可以应答了 leader向客户端发送ack
  6. leader向slave2写入
  7. slave2写完向leader发送ack表示自己写入完成

七、服务器动态上下线监听

在这里插入图片描述

7.1、案例

先在客户端创建一个结点
create /servers "servers"

Server端 (创建3个 在 server.regist(“zk1”)改成不同的名字zk1、zk2、zk3)

import org.apache.zookeeper.*;
import java.io.IOException;

public class DistributeServer01 {

    //,分割不能有空格 在程序里写connectString不可使用ip,必须使用主机名
    private String connectString = "master:2181,slave1:2181,slave2:2181";
    //超时时间
    private int sessionTimeout = 2000;
    //zk客户端
    private ZooKeeper zkClient;

    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {

        DistributeServer01 server=new DistributeServer01();
        //1.获取zk连接
        server.getConnect();
        //2.注册服务器到zk集群
        server.regist("zk1");
        //3.启动业务逻辑(睡觉)
        server.business();
    }

    private void business() throws InterruptedException {
        Thread.sleep(Long.MAX_VALUE);
    }

    private void regist(String hostname) throws InterruptedException, KeeperException {
        String s = zkClient.create("/servers/", hostname.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        System.out.println(hostname+"已经上线");
    }

    private void getConnect() throws IOException {
        zkClient= new ZooKeeper(connectString, sessionTimeout, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {

            }
        });
    }
}

Client端

import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class DistributeClient {

    //,分割不能有空格 在程序里写connectString不可使用ip,必须使用主机名
    private String connectString = "master:2181,slave1:2181,slave2:2181";
    //超时时间
    private int sessionTimeout = 2000;
    //zk客户端
    private ZooKeeper zkClient;

    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
        DistributeClient client=new DistributeClient();
        //1.获取zk连接
        client.getConnect();
        //2.监听/servers下面子节点的增加和删除
        client.getServerList();
        //3.业务逻辑(睡觉)
        client.business();
    }

    private void business() throws InterruptedException {
        Thread.sleep(Long.MAX_VALUE);
    }

    private void getServerList() throws InterruptedException, KeeperException {
        List<String> children = zkClient.getChildren("/servers", true);
        ArrayList<String> servers = new ArrayList<>();
        for (String s:children){
            try {
                byte[] data = zkClient.getData("/servers/" + s, false, null);
                servers.add(new String(data, "utf-8"));
            }catch (Exception e){}
        }
        System.out.println(servers);
    }

    private void getConnect() throws IOException {
        zkClient= new ZooKeeper(connectString, sessionTimeout, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                try {
                    getServerList();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (KeeperException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

逐步启动DistributeServer01 、DistributeServer02、DistributeServer013 启动一个看一下DistributeClient 的控制台
在这里插入图片描述

八、分布式锁

8.1、分析

  1. 接收到请求后,在/locks节点下创建一个临时顺序节点
  2. 判断自己是不是当前节点下最小的节点:是,获取到锁;不是,对前一个节点进行监听
  3. 获取到锁,处理完业务后,delete节点释放锁,然后下面的节点将收到通知,重复第二步判断
    在这里插入图片描述

8.1、案例

DistributeLock

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class DistributeLock {
    //,分割不能有空格 在程序里写connectString不可使用ip,必须使用主机名
    private String connectString = "master:2181,slave1:2181,slave2:2181";
    //超时时间
    private int sessionTimeout = 2000;
    //zk客户端
    private ZooKeeper zkClient;
    private CountDownLatch countDownLatch=new CountDownLatch(1);
    private CountDownLatch waitDownLatch=new CountDownLatch(1);
    //前一个结点的路径
    private String waitPath;
    private String currentMode;
    public  DistributeLock() throws IOException, InterruptedException, KeeperException {
        //获取连接
        zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                // connectLatch如果连接上zk可以释放
                if (watchedEvent.getState() == Event.KeeperState.SyncConnected){
                    countDownLatch.countDown();
                }
                // waitLatch需要释放
                if (watchedEvent.getType()==Event.EventType.NodeDeleted && watchedEvent.getPath().equals(waitPath)){
                    waitDownLatch.countDown();
                }
            }
        });
        //等待zk连接成功
        countDownLatch.await();
        //判断根节点locks是否存在
        Stat exists = zkClient.exists("/locks", false);
        if(exists==null){
            //创建根节点
            zkClient.create("/locks","locks".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
        }
    }
    //对zk加锁
    public  void zkLock(){
        //创建临时带序号结点
        try {
            currentMode = zkClient.create("/locks/" + "seq-", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
            //判断创建的结点是否是最小的结点 是获取锁,如果不是监听前一个结点
            List<String> children = zkClient.getChildren("/locks", false);
            //如果children只有一个值,那就直接获取锁;如果有多个节点,需要判断,谁最小
            if (children.size() == 1){
                    return;
            }else{
                Collections.sort(children);
                //获取节点名称seq-00000000
                String thisNode = currentMode.substring( "/locks/".length());
                //通过seq-00000000获取该节点在children集合的位置
                int index = children.indexOf(thisNode) ;
                //判断
                if (index == -1 ){
                    System.out.println("数据异常");}
                else if(index == 0){
                    //就一个节点,可以获取锁了
                    return;
                }else {
                    waitPath="/locks/"+children.get(index-1);
                    zkClient.getData(waitPath,true,null);
                    //等待监听
                    waitDownLatch.await();
                    return;
                }
            }
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //对zk解锁
    public  void UnzkLock(){
        //删除结点
        try {
            zkClient.delete(currentMode,-1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }
}

DistributeLockTest

import org.apache.zookeeper.KeeperException;
import java.io.IOException;
public class DistributeLockTest {
    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
      final DistributeLock distributeLock1 = new DistributeLock();
      final DistributeLock distributeLock2 = new DistributeLock();
      new Thread(()->{
          try {
              distributeLock1.zkLock();
              System.out.println("aaa线程获取锁");
              Thread.sleep(5000);
              distributeLock1.UnzkLock();
              System.out.println("aaa线程释放锁");
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      },"aaa").start();
        new Thread(()->{
            try {
                distributeLock2.zkLock();
                System.out.println("bbb线程获取锁");
                Thread.sleep(5000);
                distributeLock2.UnzkLock();
                System.out.println("bbb线程释放锁");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"bbb").start();
    }
}

九、其他

9.1、生产集群安装多少k合适

安装奇数台
生产经验:

  • 10台服务器:3台zk;
  • 20台服务器:5台zk;
  • 100台服务器:11台zk
  • 200台服务器:11台zk

服务器台数多:好处,提高可靠性;坏处:提高通信延时

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

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

相关文章

Matlab 中 global 函数实例解析

目录 global 函数 案例分析 1 案例分析 2 使用golbal的优点 1. 传递大数据的参数 2. 过多的常量需要传递 global 函数 比如在主函数里面&#xff0c;你需要设置 Nc 这个变量是一个全局变量&#xff0c;就需要声明一下&#xff1a; global Nc; 然后在子函数里面你又用到了…

EMQX 多版本发布、新增自定义函数功能

11 月&#xff0c;EMQX 开源版和企业版分别发布了多个迭代版本&#xff0c;在安全性保障和生态集成方面又有了新的提升。 MQTT 消息云服务 EMQX Cloud 推出了新功能——自定义函数&#xff0c;用户可以更方便地将 IoT 数据处理为符合数据流的数据格式。 EMQX 11 月 EMQX 开源…

记一次golang struct字符串值被挤掉(被异常修改)的问题

使用的是gofiber框架&#xff0c;在包内设置了一个全局变量来保存数据&#xff0c;如下: var list make(map[int64]*Task, 10) type Task struct {ID int64Name string }gofiber设置了两个接口&#xff0c;一个是创建&#xff1a; func Create(c *fiber.Ctx) error {task : …

投票评选小程序毕业设计,微信投票小程序系统设计与实现,微信小程序毕业设计论文怎么写毕设源码开题报告需求分析怎么做

项目背景和意义 目的&#xff1a;本课题主要目标是设计并能够实现一个基于微信小程序评选投票系统&#xff0c;前台用户使用小程序&#xff0c;后台管理使用基PHPMySql的B/S架构&#xff1b;通过后台添加资讯、管理上传投票信息、用户管理等&#xff1b;用户通过小程序登录&…

高等数学(第七版)同济大学 总习题十 (前6题)个人解答

高等数学&#xff08;第七版&#xff09;同济大学 总习题十&#xff08;前6题&#xff09; 函数作图软件&#xff1a;Mathematica 1.填空&#xff1a;\begin{aligned}&1. \ 填空&#xff1a;&\end{aligned}​1. 填空&#xff1a;​​ (1)积分∫02dx∫x2e−y2dy的值是_…

[附源码]Python计算机毕业设计Django作业管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Linux keepalived高可用集群+keepaliced+LVS

Linux keepalived高可用集群keepalicedLVS keepalivedlvs集群 环境准备 拓扑&#xff1a; 192.168.0.116 dr1 负载均衡器 192.168.0.117 dr2 负载均衡器 192.168.0.118 rs1 web1 192.168.0.119 rs2 web2 1.在master上安装配置Keepalived: yum install keepalived ipvsadm…

需求响应|动态冰蓄冷系统与需求响应策略的优化研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️❤️&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f4dd;目前更新&#xff1a;&#x1f31f;&#x1f31f;&#x1f31f;电力系统相关知识&#xff0c;期刊论文&…

WEB静态网页作业 我的家乡南宁 家乡旅游网页设计制作 简单静态HTML网页作品

家乡旅游景点网页作业制作 网页代码运用了DIV盒子的使用方法&#xff0c;如盒子的嵌套、浮动、margin、border、background等属性的使用&#xff0c;外部大盒子设定居中&#xff0c;内部左中右布局&#xff0c;下方横向浮动排列&#xff0c;大学学习的前端知识点和布局方式都有…

Spring Boot + Redis 解决重复提交问题,一文带你搞懂,最详细教程

文章目录**前言****搭建 Redis 服务 API****自定义注解 AutoIdempotent****token 创建和检验****拦截器的配置****测试用例****总结**前言 在实际的开发项目中,一个对外暴露的接口往往会面临很多次请求&#xff0c;我们来解释一下幂等的概念&#xff1a;任意多次执行所产生的影…

使用formatter方法格式化数据

前言 当你在表格中根据标识展示不同字段时&#xff0c;你发现&#xff0c;这个标识的类型有很多&#xff0c;需要一个一个判断很多行代码。当然&#xff0c;标识的类型比较少时&#xff0c;直接通过判断展示不同的字段无疑是最快的&#xff0c;如下代码。一旦匹配的标识类型有几…

java自动化接口如何获取返回值中特定的字段HttpEntity类转换成实体类对象<搬代码>

第一看一下返回值是什么样子的&#xff1a; {"msg": "查询成功","total": 9223xxx75807,"code": 200,"maps": null,"devMsg": null,"rows": [{"detxxxme": "商户来**交易10000.00元&qu…

【云原生微服务】SpringCloud Commons通用抽象

&#x1f496; Spring家族及微服务系列文章 ✨【微服务】SpringCloud中OpenFeign请求处理及负载均衡流程 ✨【微服务】SpringCloud中Ribbon的WeightedResponseTimeRule策略 ✨【微服务】SpringCloud中Ribbon的轮询(RoundRobinRule)与重试(RetryRule)策略 ✨【微服务】SpringCl…

二叉搜索树-技术点

二叉树的描述 相当于给树来个计划生育 二叉树的原理 二叉树只允许最多两个节点 二叉树节点最多有两个节点 并不是一定要有两个分支节点 如图所示: 在非空的二叉树里,具有i-1层的节点的总数不超过2的i-1次方 i>1 深度为h-1的二叉树 最多有二的h次方 -1个结点 最少有h个结…

用electron+vue+ts开发桌面应用

1.搭建项目 npm create vitelatest安装electron插件 npm install electron -D npm install vite-plugin-electron -D这里安装插件会包如下错&#xff1a; 在终端执行&#xff1a; npm config set electron_mirror https://npm.taobao.org/mirrors/electron/配置参数 在vite…

程序的翻译环境【编译链接的过程】【详解】

本期介绍&#x1f356; 主要介绍&#xff1a;代码是如何一步步的转化成可执行城西的&#xff0c;详细介绍了编译和链接的过程&#xff0c;特别是在编译还可分为预编译、编译、汇编三个阶段&#xff0c;介绍每个阶段分别干什么。&#x1f440;。 文章目录一、概述&#x1f356;二…

手写一个简单的mybatis

1.写个简单的mybatis 今天写个简单版V1.0版本的mybatis&#xff0c;可以其实就是在jdbc的基础上一步步去优化的&#xff0c;网上各种帖子都是照着源码写&#xff0c;各种抄袭&#xff0c;没有自己的一点想法&#xff0c;写代码前要先思考&#xff0c;如果是你&#xff0c;你该…

【数据库数据恢复】MS SQL数据库提示“附加数据库错误 823”怎么恢复数据?

MS SQL Server是微软公司研发的数据库管理系统&#xff0c;SQL Server是一个可扩展的、高性能的、与WindowsNT有机结合的&#xff0c;为分布式客户机/服务器所设计的数据库管理系统&#xff0c;提供基于事务的企业级信息管理系统方案。 SQL Server数据库故障情况&分析&…

RCNN学习笔记-MobileNet

Abstract 我们提出了一类叫做MobileNets的高效模型用于移动和嵌入式视觉应用。MobileNets基于一种简化的架构&#xff0c;该架构使用深度方向可分离卷积来构建轻量级深度神经网络。我们引入了两个简单的全局超参数&#xff0c;可以有效地在延迟和准确性之间进行权衡。这些超参…

套用bi模板,轻松搞定各类数据分析报表

bi模板是什么?是一个个提前预设的报表设计&#xff0c;套用后立即生效&#xff0c;轻轻松松搞定bi数据可视化分析报表。bi模板都有哪些类型&#xff1f;怎么套用&#xff1f;以奥威bi数据可视化软件为例&#xff0c;聊聊bi模板的种类和下载使用。 bi模板有哪些&#xff1f; …