2.15日学习打卡----初学Zookeeper(二)

2.15日学习打卡

目录:

  • 2.15日学习打卡
  • 一. Zookeeper部署运行
    • 伪集群安装
    • 集群安装
    • 服务管理
  • 二. Zookeeper系统模型
    • 数据模型
    • 节点特性
    • 客户端命令行
    • 节点数据信息
    • Watcher监听机制
    • 权限控制 ACL
  • 三. 原生api操作Zookeeper
  • 四. zkclient库操作Zookeeper
  • 五. Apache Curator操作Zookeeper
  • 六. Zookeeper高级
    • 四字命令
    • 选举机制

一. Zookeeper部署运行

伪集群安装

在这里插入图片描述
下载Zookeeper

在这里插入图片描述
选择第二个点击Download
在这里插入图片描述
下载最新版本即可
在这里插入图片描述
下载后将文件上传值虚拟机
可以使用xftp或者rz命令
将上传后的Zookeeper 解压后移动到 usr/local目录下

tar -zxvf apache-zookeeper-3.9.1-bin.tar.gz -C /usr/local

重命名文件夹

mv apache-zookeeper-3.9.1-bin zookeeper-3.9.1

修改配置文件

cd /usr/local/zookeeper/config
mv zoo_sample.cfg zoo.cfg

修改zoo.cfg

#The number of milliseconds of each tick
tickTime=2000initLimit=10
syncLimit=5
dataDir=/usr/local/zookeeper/zkdata
dataLogDir=/usr/local/zookeeper/zklogs
clientPort=2181
在这里插入图片描述

创建数据持久化目录

mkdir /usr/local/zookeeper/zkdata
mkdir /usr/local/zookeeper/zklogs

启动zookeeper服务(进入bin目录)

./zkServer.sh start

查看Zookeeper运行状态

zkServer.sh status

jps 查看进程
在这里插入图片描述
可以通过./zkCli.sh来判断是否搭建成功

./zkCli.sh
在这里插入图片描述

集群安装

在这里插入图片描述
环境准备(3个虚拟机)

192.168.66.100
192.168.66.110
192.168.66.120

解压zookeeper

tar -zxvf apache-zookeeper-3.6.3.tar.gz -C /usr/local

修改配置文件

cd /usr/local/zookeeper/config
mv zoo_sample.cfg zoo.cfg

修改zoo.cfg

添加
server.1=192.168.66.101:2888:3888
server.2=192.168.66.102:2888:3888
server.3=192.168.66.103:2888:3888

创建数据持久化目录和日志目录

对3台节点,都创建zkdata目录 。

mkdir /usr/local/zookeeper/zkdata
mkdir /usr/local/zookeeper/zklogs

在工作目录中生成myid文件

第一台机器上: echo 1 > /usr/local/zookeeper/zkdata/myid
第二台机器上: echo 2 > /usr/local/zookeeper/zkdata/myid
第三台机器上: echo 3 > /usr/local/zookeeper/zkdata/myid

启动zookeeper集群
zookeeper没有提供自动批量启动脚本,需要手动一台一台地起zookeeper进程 在每一台节点上,运行命令:

bin/zkServer.sh start

注意:
启动后,用jps应该能看到一个进程:QuorumPeerMain。光有进程不代表zk已经正常服务,需要用命令检查状态:bin/zkServer.sh status 能看到角色模式:为leader或follower,即正常了。

服务管理

在这里插入图片描述

脚本说明
zkCleanup清理Zookeeper历史数据,包括事务日志文件和快照数据文件
zkCliZookeeper的简易客户端
zkEnv设置Zookeeper的环境变量
zkServer Zookeeper服务器的启动、停止和重启脚本

配置环境变量

修改文件
vim /etc/profile

export ZOOKEEPER_HOME=/usr/local/zookeeper
export PATH=$PATH:$JAVA_HOME/bin:$ZOOKEEPER_HOME/bin

生效环境变量

source /etc/profile

启动服务
如何启动zookeeper服务。

语法结构

sh zkServer.sh start

停止服务
语法结构:

sh zkServer.sh stop

查看zookeeper状态
语法结构:

sh zkServer.sh status

设置一键启动/一键停止脚本
编写一键启停脚本 vim zkStart-all.sh

#验证传入的参数
if [ $# -ne 1 ];then
   echo "无效参数,用法为: $1 
{start|stop|restart|status}"
   exit
fi
#遍历所有节点
for host in 192.168.66.100 192.168.66.110
192.168.66.120
do
   echo "========== $host 正在 $1 ========= "
   #发送命令给目标机器
   ssh $host "source /etc/profile;
/usr/local/zookeeper/bin/zkServer.sh $1"
done

二. Zookeeper系统模型

数据模型

在这里插入图片描述
在Zookeeper中,可以说 Zookeeper中的所有存储的数据是由znode组成的,节点也称为 znode,并以 key/value 形式存储数据


在这里插入图片描述

介绍:
整体结构类似于 linux 文件系统的模式以树形结构存储。其中根路径以 / 开头

保存数据
在这里插入图片描述

注意:
以 key/value 形式存储数据。key就是znode的节点路径,比如 /java , /server。

节点特性

在这里插入图片描述
znode节点类型

ZooKeeper 节点是有生命周期的,这取决于节点的类型。节点类型可以分为持久节点、临时节点,以及时序节点,具体在节点创建过程中,一般是组合使用,可以生成以下 4 种节点类型。
在这里插入图片描述
持久节点

持久节点是zookeeper中最常见的一种节点类型。所谓持久节点,是指改数据节点被创建后,就会一直存在与zookeeper服务器上,直到有删除操作来主动清除这个节点。
示例:

/java  spring
/jjy  zbjjy

持久顺序节点

这类节点的基本特性和上面的节点类型是一致的。额外的特性是,在ZK中,每个父节点会为他的第一级子节点维护一份时序,会记录每个子节点创建的先后顺序。
在这里插入图片描述
示例:

/java00000000000001  spring
/jjy00000000000001  zbjjy

临时节点
在这里插入图片描述

区别:
和持久节点不同的是,临时节点的生命周期和客户端会话绑定。也就是说,如果客户端会话失效,那么这个节点就会自动被清除掉。注意,这里提到的是会话失效,而非连接断开。另外,在临时节点下面不能创建子节点。

临时顺序节点

临时顺序节点的基本特性和临时节点是一致的,同样是在临时节点的基础上,添加了顺序的特性。

示例:

/jjy0000000000000001  zbjjy
/jjy0000000000000002  zbjjy
/jjy0000000000000003  zbjjy

客户端命令行

在这里插入图片描述

创建

创建ZK节点

语法结构:

create [-s] [-e] path data acl

参数
-s:顺序节点
-e:临时节点
默认情况下,不添加-s或者-e参数的,创建的是持久节点。

实例:

[zk: localhost:2181(CONNECTED) 0]create /zk-book jjy

读取

读取节点信息ls命令和set命令。

ls命令
语法结构:

ls path [watch]

实例:

ls /

注意:
第一次部署的ZooKeeper集群,默认在根节点“1”下面有一个叫作/zookeeper的保留节点。

get命令
使用get命令,可以获取zookeeper指定节点的数据内容和属性信息。

语法格式:

get path [watch]

示例:

get /zk-book

更新

使用set命令,可以更新指定节点的数据内容。

语法结构:

set path data [version]

示例:

set /java springmvc

参数:
data就是要更新的新内容。注意,set命令后面还有一个version参数,在ZooKeeper 中,节点的数据是有版本概念的,这个参数用于指定本次更新操作是基于ZNode的哪一个数据版本进行的。

删除

删除zookeeper上的指定节点。

语法结构:

delete path [version]

示例:

create /zk-book 123
create /zk-book/child 12345
delete /zk-book

参数:
如果节点包含子节点就报错。

节点数据信息

在这里插入图片描述

节点的状态结构

每个节点都有属于自己的状态信息,这就很像每个人的身份信息一样。

语法结构:

[zk: localhost:2181(CONNECTED) 15] stat /a
cZxid = 0x300000014
ctime = Thu Dec 30 15:05:07 CST 2021
mZxid = 0x300000014
mtime = Thu Dec 30 15:05:07 CST 2021
pZxid = 0x300000015
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 1
numChildren = 1

查看节点类型

语法结构:

create 参数  /java  spring

参数
-e:临时节点
-s:顺序节点
默认不写就是持久型节点

在这里插入图片描述

Watcher监听机制

在这里插入图片描述
ZooKeeper 提供了分布式数据的发布/订阅功能。一个典型的发布/订阅模型系统定义了一种一对多的订阅关系,能够让多个订阅者同时监听某一个主题对象,当这个主题对象自身状态变化时,会通知所有订阅者,使它们能够做出相应的处理。
在这里插入图片描述

注意:
在ZooKeeper中,引入了Watcher机制来实现这种分布式的通知功能。ZooKeeper 允许客户端向服务端注册一个 Watcher 监听,当服务端的一些指定事件触发了这个Watcher,那么就会向指定客户端发送一个事件通知来实现分布式的通知功能。

监听机制

监听节点变化
语法结构:

ls -w path

参数:
命令如果使用watch,那么监听的是节点的变化,而不是值的变化。

监听节点的值的变化
语法结构:

get -w path

参数:
watch监听机制只能够使用一次,如果下次想要使用,必须重新监听,就比如ls path watch命令,只能监听节点路径的改变一次,如果还想监听,那么需要再执行一次ls path watch命令。

权限控制 ACL

在这里插入图片描述
在ZooKeeper的实际使用中,我们的做法往往是搭建一个共用的ZooKeeper集群,统一为若干个应用提供服务。在这种情况下,不同的应用之间往往是不会存在共享数据的使用场景的,因此需要解决不同应用之间的权限问题。

ACL 权限控制

  1. 权限模式(Schema)
  2. 授权对象(ID)
  3. 权限(Permission)

参数:

  1. ZooKeeper的权限控制是基于每个znode节点的,需要对每个节点设置权限
  2. 每个znode支持设置多种权限控制方案和多个权限
  3. 子节点不会继承父节点的权限,客户端无权访问某节点,但可能可以访问它的子节点

例子:

setAcl /test2 ip:128.0.0.1:crwda

在这里插入图片描述
schema

ZooKeeper内置了一些权限控制方案,可以用以下方案为每个节点设置权限:

方案描述
world只有一个用户:anyone,代表所有人(默认)
ip使用IP地址认证
auth使用已添加认证的用户认证
digest使用“用户名:密码”方式认证

在这里插入图片描述
id

授权对象ID是指,权限赋予的用户或者一个实体,例如:IP 地址或
者机器。授权模式 schema 与 授权对象 ID 之间关系:

权限模式授权对象
IP通常是一个IP地址或是IP段,例如“192.168.66.101”
Digest自定义,通常是“username:BASE64(SHA-1(username:password))”
World只有一个ID:“anyone”
Super与Digest模式一致

在这里插入图片描述

权限permission

权限ACL简写描述
CREATEc可以创建子节点
DELETEd可以删除子节点(仅下一级节点)
READr可以读取节点数据及显示子节点列表
WRITEw可以设置节点数据
ADMINa可以设置节点访问控制列表权限

在这里插入图片描述
权限相关命令

命令使用方式描述
getAclgetAcl读取ACL权限
setAclsetAcl设置ACL权限
addauthaddauth添加认证用户

实战
World方案
语法格式:

setAcl <path> world:anyone:<acl>

客户端实例

[zk: localhost:2181(CONNECTED) 0] create /node1 1
Created /node1
[zk: localhost:2181(CONNECTED) 1] getAcl /node1 'world,'anyone #默认为world方案
: cdrwa #任何人都拥有所有权限

IP方案

语法格式:

setAcl <path> ip:<ip>:<acl>

参数
:可以是具体IP也可以是IP/bit格式,即IP转换为二进制,匹配前bit位,如192.168.0.0/16匹配192.168…

客户端实例

#创建节点
[zk: localhost:2181(CONNECTED) 0] create /node2 1
Created /node2
#设置权限
[zk: localhost:2181(CONNECTED) 1] setAcl /node2 ip:192.168.66.110:cdrwa #设置IP:192.168.66.110
拥有所有权限
cZxid = 0x1900000239
#使用IP非 192.168.66.101 的机器
[zk: localhost:2181(CONNECTED) 0] get /node2
Authentication is not valid : /node2 #没有权限

Auth方案
语法格式:

setAcl <path> auth:<user>:<acl>

添加认证用户

addauth digest <user>:<password>

客户端实例

#创建节点
[zk: localhost:2181(CONNECTED) 0] create /node3
1
Created /node3
#添加认证用户
[zk: localhost:2181(CONNECTED) 1] addauth digest jjy:123456
#设置权限
[zk: localhost:2181(CONNECTED) 2] setAcl /node3 auth:yoonper:cdrwa
#获取权限
[zk: localhost:2181(CONNECTED) 3] getAcl /node3 'digest,'jjy:UvJWhBril5yzpEiA2eV7bwwhfLs=: cdrwa

刚才已经添加认证用户,可以直接读取数据,断开会话重连需要重新addauth添加认证用户

[zk: localhost:2181(CONNECTED) 3] get /node3

Digest方案

语法格式:

setAcl <path> digest:<user>:<password>:<acl>

这里的密码是经过SHA1及BASE64处理的密文,在SHELL中可以通
过以下命令计算:

echo -n <user>:<password> | openssl dgst -binary -sha1 | openssl base64

先来计算一个密文

echo -n baizhan:123456 | openssl dgst -binary -sha1 | openssl base64
UvJWhBril5yzpEiA2eV7bwwhfLs=

客户端实例

#创建节点
[zk: localhost:2181(CONNECTED) 0] create /node4 1
Created /node4
#使用是上面算好的密文密码添加权限:
[zk: localhost:2181(CONNECTED) 1] setAcl /node4 digest:jjy:UvJWhBril5yzpEiA2eV7bwwhfLs=:cdr
wa
 #获取节点数据没有权限
[zk: localhost:2181(CONNECTED) 3] get /node4
Authentication is not valid : /node4
#添加认证用户
[zk: localhost:2181(CONNECTED) 4] addauth digest jjy:123456
#成功读取数据
[zk: localhost:2181(CONNECTED) 5] get /node4
1

三. 原生api操作Zookeeper

在这里插入图片描述
利用Zookeeper官方的原生java api进行连接,然后演示一些创建、删除、修改、查询节点的操作。

引入依赖

<dependencies>
  <dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.8</version>
  </dependency>
</dependencies>

创建会话

package com.jjy;

import org.apache.zookeeper.ZooKeeper;

import java.io.IOException;

public class ZkMain {
    public static void main(String[] args) throws IOException {
        /**
         * 创建一个 Zookeeper 的实例
         * 此处为一个集群,Zookeeper 的 ip 之间用逗号隔开
         *
         * 参数解释:
         * param 1 - Zookeeper 的实例 ip ,此处是一个集群,所以配置了多个 ip,用逗号隔开
         * param 2 - session 过期时间,单位秒 (1000)
         * param 3 - 监视者,用于获取监听事件 (MyWatch)
         */
        //创建一个会话
        ZooKeeper zooKeeper = new ZooKeeper("192.168.66.100:2181,192.168.66.110:2181,192.168.66.120:2181", 4000, null);
        System.out.println(zooKeeper.getState());
    }
}

创建节点

private void createNodeSync() throws KeeperException, InterruptedException {
  String path = "/poype_node";
  /*
  *znode名称
  *节点数据
  *设置权限
  *znode类型
  *
  */
  String nodePath = zooKeeper.create(path, "123".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
  System.out.println(nodePath);
}

znode 类型有四种

  1. PERSISTENT - 持久化目录节点,客户端与zookeeper断开连接后,该节点依旧存在
  2. PERSISTENT_SEQUENTIAL - 持久化,并带有序列号
  3. EPHEMERAL - 临时目录节点,客户端与zookeeper断开连接后,该节点被删除
  4. EPHEMERAL_SEQUENTIAL - 临时,并带有序列号

删除节点
同步方式删除一个节点:

private void deleteSync() throws KeeperException, InterruptedException {
   zooKeeper.delete("/node_1", 12);
}

读取数据

private void getDataSync() throws KeeperException, InterruptedException {
   Stat stat = new Stat();
   // getData的返回值是该节点的数据值,节点的状态信息会赋值给stat对象
   byte[] data = zooKeeper.getData("/node_1",true, stat);
   System.out.println(new String(data));
   System.out.println(stat);
}

参数:
znode 名称 (/zoo)
监视者,用于获取监控事件 (MyWatch)
Zookeeper 实例信息和数据信息 (stat)

更新数据

Stat stat = zooKeeper.setData("/poype_node2", "poype5211314".getBytes(), 1);

参数:
param1:znode名称
param2:节点数据
param3:该节点的版本

检测节点是否存在

private void existSync() throws KeeperException, InterruptedException {
   Stat stat = zooKeeper.exists("/poype_node2", true);
   System.out.println(stat);
}

参数:
param1:znode 名称 (/zoo)
param2:监视者,用于获取监控事件 (MyWatch)

注册监听getChilren

通过zkCli.getchildren(“/”,new watch()){}来注册监听,监听的是整个根节点,但是这个监听只能监听一次。线程休眠是为了让监听等待事件发生,不然会随着程序直接运行完。

public class WatchDemo1 {
    
    static List<String> children = null;
    public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
        


        ZooKeeper zkCli = new ZooKeeper("192.168.50.183:2181,192.168.50.184:2181,192.168.50.185:2181", 3000, new Watcher() {
                
                //监听回调
                @Override
                public void process(WatchedEvent event) {
                    System.out.println("正在监听中.....");
                }
            });
        
            //监听目录
            children = zkCli.getChildren("/", new Watcher() {
            
            @Override
            public void process(WatchedEvent event) {
                
                System.out.println("监听路径为:" + event.getPath());
                System.out.println("监听的类型为:" + event.getType());
                System.out.println("数据被2货修改了!!!");
                
                for(String c:children) {
                    System.out.println(c);
                }
            }
        }); 
            Thread.sleep(Long.MAX_VALUE);
    }   
}

注册监听getData

getData监听的为一个节点,同样只监听一次,返回的是该节点的内容。

public class WatchDemo {
    public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
        ZooKeeper zkCli = new ZooKeeper("192.168.50.183:2181,192.168.50.184:2181,192.168.50.185:2181", 3000, new Watcher() {
            
            //监听回调
            @Override
            public void process(WatchedEvent event) {
                
            }
        });
        
        byte[] data = zkCli.getData("/hunter", new Watcher() {
            //监听的具体内容
            @Override
            public void process(WatchedEvent event) {
                System.out.println("监听路径为:" + event.getPath());
                System.out.println("监听的类型为:" + event.getType());
                System.out.println("数据被2货修改了!!!");
            }
        }, null);
        System.out.println(new String(data));
        Thread.sleep(Long.MAX_VALUE);
    }
}


测试

package com.jjy;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

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

public class ZkMain {
    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
        /**
         * 创建一个 Zookeeper 的实例
         * 此处为一个集群,Zookeeper 的 ip 之间用逗号隔开
         *
         * 参数解释:
         * param 1 - Zookeeper 的实例 ip ,此处是一个集群,所以配置了多个 ip,用逗号隔开
         * param 2 - session 过期时间,单位秒 (1000)
         * param 3 - 监视者,用于获取监听事件 (MyWatch)
         */
        //创建一个会话
        ZooKeeper zooKeeper = new ZooKeeper("192.168.66.100:2181,192.168.66.110:2181,192.168.66.120:2181", 4000, null);
        System.out.println(zooKeeper.getState());
        /*
         *znode名称
         *节点数据
         *设置权限
         *znode类型
         *
         */
//        //创建结点
//        String s = zooKeeper.create("/node1", "1".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
//        System.out.println(s+"创建成功");

        //判断结点是否存在
        Stat exists = zooKeeper.exists("/node1", null);
        System.out.println(exists);

        //删除结点
        //zooKeeper.delete("/node1", -1);
        //修改结点
        //zooKeeper.setData("/node1","jjy".getBytes(),-1);
        //获取结点的数据
        byte[] data = zooKeeper.getData("/node1", null, null);
        System.out.println(new String(data));
        //获取节点
        List<String> children = zooKeeper.getChildren("/node1", null);
        for(String child : children){
            System.out.println(child);
        }


    }
}
package com.jjy;

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

import java.io.IOException;

public class ZkWacher {
    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
        /**
         * 创建一个 Zookeeper 的实例
         * 此处为一个集群,Zookeeper 的 ip 之间用逗号隔开
         *
         * 参数解释:
         * param 1 - Zookeeper 的实例 ip ,此处是一个集群,所以配置了多个 ip,用逗号隔开
         * param 2 - session 过期时间,单位秒 (1000)
         * param 3 - 监视者,用于获取监听事件 (MyWatch)
         */
        //创建一个会话
        ZooKeeper zooKeeper = new ZooKeeper("192.168.66.100:2181,192.168.66.110:2181,192.168.66.120:2181", 4000, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                System.out.println("正在监听");
            }
        });
//       //注册监听机制 监听节点
//        zooKeeper.getChildren("/node1",new Watcher() {
//
//            @Override
//            public void process(WatchedEvent watchedEvent) {
//                //监听的路径
//                System.out.println(watchedEvent.getPath());
//                //监听类型
//                System.out.println(watchedEvent.getType());
//                System.out.println("节点被修改了");
//            }
//        });
        //监听数据
        zooKeeper.getData("/root",new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                //监听的具体内容
                    System.out.println("监听路径为:" + event.getPath());
                    System.out.println("监听的类型为:" + event.getType());
                    System.out.println("数据被2货修改了!!!");
            }
        },null);
        Thread.sleep(Long.MAX_VALUE);

    }

}

四. zkclient库操作Zookeeper

在这里插入图片描述

使用zookeeper遇到问题:
重复注册watcher
session失效重连
异常处理(删除节点不能有子节点,新增节点必须有父节点等)

zkclient是Github上一个开源的Zookeeper客户端,在Zookeeper原生 API接口之上进行了包装,是一个更加易用的Zookeeper客户端。同时Zkclient在内部实现了诸如Session超时重连,Watcher反复注册等功能,从而提高开发效率。

添加依赖

<dependency>
   <groupId>com.101tec</groupId>
   <artifactId>zkclient</artifactId>
   <version>0.10</version>
</dependency>

创建会话

String connStr = "192.168.66.100:2181";
ZkClient zk = new ZkClient(connStr);

创建节点

String res = zk.create("/root", "jjy",
CreateMode.PERSISTENT);

修改节点数据

zk.writeData("/root", "zbjjy");

获取节点数据

String res = zk.readData("/root");

删除节点

zk.delete("/root");

注册数据监听

    zk.subscribeDataChanges("/root/ghz", new IZkDataListener() {


       @Override
       public void handleDataDeleted(String arg0) throws Exception {
         System.err.println("数据删除:" + arg0);
       }
       @Override
       public void handleDataChange(String arg0, Object arg1) throws Exception {
         System.err.println("数据修改:" + arg0 + "------" + arg1);


       }
     });

注册节点监听

zk.subscribeChildChanges("/root", (arg0, arg1) -> {
       System.err.println("子节点发生变化:" + arg0);
       arg1.forEach(f -> {
         System.out.println("content:" + f);
       });
     });

测试

package com.jjy;

import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.apache.zookeeper.CreateMode;

import java.util.List;

public class ZkClientMain {
    public static void main(String[] args) throws InterruptedException {
        //创建会话
        ZkClient zk = new ZkClient("192.168.66.100:2181,192.168.66.110:2181,192.168.66.120:2181");

       //获取子节点
        List<String> children = zk.getChildren("/node1");
        for (String child : children) {
            System.out.println(child);
        }
        //创建结点
        zk.create("/node2","2", CreateMode.PERSISTENT);
        System.out.println("创建节点成功");
        //修改结点数据
        zk.writeData("/node2","jjy");
        //获取数据
        String o = zk.readData("/node2");
        System.out.println(o);
        //删除数据
        zk.delete("/node2");
        //注册节点监听事件
        zk.subscribeChildChanges("/node1", new IZkChildListener() {
            @Override
            public void handleChildChange(String s, List<String> list) throws Exception {
                System.out.println("数据改变了");
                list.forEach(f->{System.out.println(f);});
            }
        });
        //注册结点数据
        zk.subscribeDataChanges("/node2", new IZkDataListener() {
            @Override
            public void handleDataChange(String s, Object o) throws Exception {
                System.out.println("数据改变了");
            }

            @Override
            public void handleDataDeleted(String s) throws Exception {
                System.out.println("数据删除了");
            }
        });
     Thread.sleep(Long.MAX_VALUE);
    }
}

五. Apache Curator操作Zookeeper

在这里插入图片描述
Curator是 Netflix公司开源的一套ZooKeeper客户端框架。和ZkClient一样,Curator解决了很多ZooKeeper客户端非常底层的细节开发工作,包括连接重连、反复注册Watcher和NodeExistsException异常等,目前已经成为了Apache的顶级项目,是全世界范围内使用最广泛的ZooKeeper客户端之一

Curator包
在这里插入图片描述

添加Maven依赖

<dependency>
   <groupId>org.apache.curator</groupId>
   <artifactId>curator-recipes</artifactId>
   <version>4.2.0</version>
</dependency>

创建会话

 String connStr = "192.168.66.100:2181";
    CuratorFramework cur= CuratorFrameworkFactory.builder()
         .connectString(connStr)
         .connectionTimeoutMs(5000)
         .retryPolicy(new ExponentialBackoffRetry(1000,3))
         .build();
    cur.start();//连接

创建节点

cur.create().withMode(CreateMode.PERSISTENT)
         .forPath("/root", "jjy".getBytes());

删除数据节点

cur.delete().forPath("/root");

注意:
此方法只能删除叶子节点,否则会抛出异常。

删除一个节点,并且递归删除其所有的子节点

cur.delete().deletingChildrenIfNeeded().forPath("/root");

删除一个节点,强制指定版本进行删除

cur.delete().withVersion(10086).forPath("path");

删除一个节点,强制保证删除

cur.delete().guaranteed().forPath("path");

注意:
guaranteed()接口是一个保障措施,只要客户端会话有效,那么Curator会在后台持续进行删除操作,直到删除节点成功。

注意:上面的多个流式接口是可以自由组合的,例如:

cur.delete().guaranteed().deletingChildrenIfNeeded().withVersion(10086).forPath("/root");

读取数据节点数据

读取一个节点的数据内容

cur.getData().forPath("/root");

注意:
此方法返的返回值是byte[ ];

读取一个节点的数据内容,同时获取到该节点的stat

Stat stat = new Stat();
client.getData().storingStatIn(stat).forPath("path");

更新数据节点数据
更新一个节点的数据内容

client.setData().forPath("path","data".getBytes());

注意:
该接口会返回一个Stat实例;

更新一个节点的数据内容,强制指定版本进行更新

client.setData().withVersion(10086).forPath("path","data".getBytes());

检查节点是否存在

client.checkExists().forPath("path");

注意:
该方法返回一个Stat实例,用于检查ZNode是否存在的操作. 可以调用额外的方法(监控或者后台处理)并在最后调用forPath()指定要操作的ZNode

获取某个节点的所有子节点路径

client.getChildren().forPath("path");

测试

package com.jjy;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;

import java.util.List;

public class CuratorMain {
    public static void main(String[] args) throws Exception {
        //创建会话
        String connStr = "192.168.66.100:2181,192.168.66.110:2181,192.168.66.120:2181";
        CuratorFramework cur= CuratorFrameworkFactory.builder()
                .connectString(connStr)
                .connectionTimeoutMs(5000)
                .retryPolicy(new ExponentialBackoffRetry(1000,3))
                .build();
        //连接
        cur.start();//连接
        //创建节点
        cur.create().withMode(CreateMode.PERSISTENT).forPath("/node3","3".getBytes());

        //获取数据
        byte[] bytes = cur.getData().forPath("/node3");
        System.out.println(new String(bytes));

        //删除结点
        cur.delete().forPath("/node3");

        //删除的结点有子节点
        cur.delete().deletingChildrenIfNeeded().forPath("/root");
        //修改结点
        cur.setData().forPath("/node3","jjy".getBytes());
        //获取某个结点的所有子节点
        List<String> strings = cur.getChildren().forPath("/node3");
        strings.forEach(f->{System.out.println(f);});

        //监听机制
        NodeCache nodeCache = new NodeCache(cur, "/node3");
        nodeCache.getListenable().addListener(()->{
            System.out.println("被修改了");
        });
        nodeCache.start();
        Thread.sleep(Long.MAX_VALUE);


    }
}

六. Zookeeper高级

四字命令

在这里插入图片描述
之前使用stat命令来验证ZooKeeper服务器是否启动成功,这里的stat命令就是ZooKeeper 中最为典型的命令之一。ZooKeeper中有很多类似的命令,它们的长度通常都是4个英文字母,因此我们称之为“四字命令”。

添加配置
vim zoo.cfg

4lw.commands.whitelist=*

四字命令

conf

输出Zookeeper相关服务的详细配置信息,如客户端端口,数据存储路径、最大连接数、日志路径、数据同步端口、主节点推举端口、session超时时间等等。

语法结构:

echo conf| nc localhost 2181

注意:
注意,conf命令输出的配置信息仅仅是输出一些最基本的配置参数。另外,conf命令会根据当前的运行模式来决定输出的信息。如果是单机模式(standalone), 就不会输出诸如initLimit.syncLimit、electionAlg 和electionPort等集群相关的配置信息。

cons
cons 命令用于输出当前这台服务器上所有客户端连接的详细信息,包括每个客户端的客户端IP、会话ID和最后一次与服务器交互的操作类型等。

语法结构:

echo cons | nc localhost 2181

ruok

ruok命令用于输出当前ZooKeeper服务器是否正在运行。该命令的名字非常有趣,其谐音正好是“Are you ok”。执行该命令后,如果当前ZooKeeper服务器正在运行,那么返回“imok”, 否则没有任何响应输出。

语法结构:

echo ruok | nc localhost 2181

stat

stat命令用于获取ZooKeeper服务器的运行时状态信息,包括基本的ZooKeeper版本、打包信息、运行时角色、集群数据节点个数等信息,另外还会将当前服务器的客户端连接信息打印出来。

语法结构:

echo stat | nc localhost 2181

注意:
除了一些基本的状态信息外,stat命令还会输出一些服务器的统计信息,包括延迟情况、收到请求数和返回的响应数等。注意,所有这些统计数据都可以通过srst命令进行重置。

mntr

列出集群的关键性能数据,包括zk的版本、最大/平均/最小延迟数、数据包接收/发送量、连接数、zk角色(Leader/Follower)、node数量、watch数量、临时节点数。

语法结构:

echo mntr | nc localhost 2181

选举机制

在这里插入图片描述
核心选举原则
在这里插入图片描述
选举机制流程
在这里插入图片描述
选择机制中的概念

Serverid:服务器ID

比如有三台服务器,编号分别是1,2,3。

编号越大在选择算法中的权重越大。

Zxid:数据ID
服务器中存放的最大数据ID.

值越大说明数据越新,在选举算法中数据越新权重越大。

Epoch:逻辑时钟

或者叫投票的次数,同一轮投票过程中的逻辑时钟值是相同的。每
投完一次票这个数据就会增加,然后与接收到的其它服务器返回的
投票信息中的数值相比,根据不同的值做出不同的判断。

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!
在这里插入图片描述

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

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

相关文章

不同的AI修改同一篇文章标题

提问AI 我写了一篇文章&#xff0c;请帮我把标题重新改一下&#xff1a;“比较不同AI分析同一个错误代码及给出解决方案的能力&#xff08;结果出我意料&#xff09;” 这篇文章的原地址为&#xff1a;https://blog.csdn.net/snans/article/details/136132211 答案对比结果&am…

RegExp正则表达式左限定右限定左右限定,预查询,预查寻,断言 : (?<= , (?= , (?<! , (?!

RegExp正则表达式左限定右限定左右限定,预查询,预查寻,断言 : (?< , (? , (?<! , (?! 有好多种称呼 (?< , (? , (?<! , (?! 有好多种称呼 , 我称为: 左限定, 右限定, 左否定, 右否定 (?<左限定)    (?右限定)(?<!左否定)    (?!右限定) 再…

Linux|centos7下的编译|ffmpeg的二进制安装

Windows版本的ffmpeg&#xff1a; ###注意&#xff0c;高版本可能必须要windows10以及以上才支持&#xff0c;win7估计是用不了的 下载地址&#xff1a;Builds - CODEX FFMPEG gyan.dev 或者这个下载地址&#xff1a;https://github.com/BtbN/FFmpeg-Builds/releases 这两个…

C++面试宝典第28题:寻找丢失的数字

题目 给定一个包含n个整数的数组nums,其中nums[i]在区间[1, n]内。请找出所有在[1, n]范围内,但没有出现在nums中的数字,并以数组的形式返回结果。 示例1: 输入:nums = [4, 3, 2, 7, 8, 2, 3, 1] 输出:[5, 6] 示例2: 输入:nums = [1, 1] 输出:[2] 解析 初看这道题,…

基于飞腾ARM+FPGA国产化计算模块联合解决方案

联合解决方案概述 随着特殊领域电子信息系统对自主创新需求的日益提升&#xff0c;需不断开展国产抗恶劣环境计算整机及模块产 品的研制和升级。特殊领域电子信息系统的自主创新&#xff0c;是指依靠自身技术手段和安全机制&#xff0c;实现信息系统从硬 件到软件的自主研发…

阿里云香港服务器详解_CN2线路测试_BGP多线精品测试

阿里云香港服务器中国香港数据中心网络线路类型BGP多线精品&#xff0c;中国电信CN2高速网络高质量、大规格BGP带宽&#xff0c;运营商精品公网直连中国内地&#xff0c;时延更低&#xff0c;优化海外回中国内地流量的公网线路&#xff0c;可以提高国际业务访问质量。阿里云服务…

【python】网络爬虫与信息提取--正则表达式

一、正则表达式 正则表达式是用来简洁表达一组字符串的表达式。是通用的字符串表达框架&#xff0c;简洁表达一组字符串的表达式&#xff0c;针对字符串表达“简洁”和“特征”思想的工具&#xff0c;判断某字符串的特征归属。 用处&#xff1a;表达文本类型的特征&#xff1b;…

【JavaEE】_HTTP请求报头header

目录 1. Host 2. Content-Length与Content-Type 2.1 Content-Length 2.2 Content-Type 3. User-Agent&#xff08;UA&#xff09; 4. Referer 5. Cookie header的整体格式是“键值对”结构&#xff0c;一行是一个键值对&#xff0c;这些键值对都是HTTP定义好的、有特殊含…

【Leetcode刷题笔记】27. 移除元素

原题链接 Leetcode 27. 移除元素 题目 给你一个数组 nums 和一个值 val&#xff0c;你需要原地移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并原地修改输入数组。元素的顺序可以改变。…

算法练习-赎金信(思路+流程图+代码)

难度参考 难度&#xff1a;中等 分类&#xff1a;哈希表 难度与分类由我所参与的培训课程提供&#xff0c;但需要注意的是&#xff0c;难度与分类仅供参考。且所在课程未提供测试平台&#xff0c;故实现代码主要为自行测试的那种&#xff0c;以下内容均为个人笔记&#xff0c;旨…

C#,整数转为短字符串(Short string)的加解密算法与源代码

1 整数转为短字符串的应用 网站生成的动态 URL 往往以内容序列号id为标识与参数&#xff0c;比如&#xff1a; http://www.jerry.com/tom.aspx?id1 使用 Web Rewrite&#xff0c;可以实现网页静态化&#xff0c;称为&#xff1a; http://www.jerry.com/content/1.html 对…

FlashMeeting(基于FFmpeg+openCV)视频语音通讯系统

Web端体验地址&#xff1a;https://download.csdn.net/download/XiBuQiuChong/88805337 客户端下载地址&#xff1a;https://download.csdn.net/download/XiBuQiuChong/88805337 FlashMeeting(基于FFmpegopenCV)是一整套先进的以FFmpegopenCV技术为基础的视频语音通讯系统。利…

数据库设计、JDBC、数据库连接池

数据库设计 数据库设计概念 数据库设计就是根据业务 系统的具体需求&#xff0c;结合我们所选用的DBMS,为这个业务系统构造出最优的数据存储模型。建立数据库中的表结构以及表与表之间的关联关系的过程。有哪些表?表里有哪些字段?表和表之间有什么关系? 数据库设计的步骤…

Java并发基础:ConcurrentSkipListSet全面解析!

内容概要 ConcurrentSkipListSet类在多线程环境下&#xff0c;它能够轻松应对大量的插入、删除和查找操作&#xff0c;同时保持数据的完整性和一致性&#xff0c;其内部基于跳表数据结构的实现&#xff0c;确保了即使在处理大规模数据时&#xff0c;也能具有出色的性能表现。 …

基于微信小程序的健身房私教预约系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

类的构造方法

在类中&#xff0c;出成员方法外&#xff0c;还存在一种特殊类型的方法&#xff0c;那就是构造方法。构造方法是一个与类同名的方法&#xff0c;对象的创建就是通过构造方法完成的。每个类实例化一个对象时&#xff0c;类都会自动调用构造方法。 构造方法的特点&#xff1a; 构…

文件上传漏洞--Upload-labs--Pass01--前端绕过

一、前端绕过原理 通俗解释&#xff0c;我们将写有恶意代码的php后缀文件上传到网页&#xff0c;网页中的javascript代码会先对文件的后缀名进行检测&#xff0c;若检测到上传文件的后缀名为非法&#xff0c;则会进行alert警告。若想上传php后缀的文件&#xff0c;就要想办法对…

Acwing---877. 扩展欧几里得算法

扩展欧几里得算法 1.题目2.基本思想3.代码实现 1.题目 给定 n n n 对正整数 a i ai ai, b i bi bi&#xff0c;对于每对数&#xff0c;求出一组 x i xi xi, y i yi yi&#xff0c;使其满足 a i x i b i y i g c d ( a i , b i ) aixibiyigcd(ai,bi) aixibiyigcd(ai,bi)…

K8s进阶之路-安装部署K8s

参考&#xff1a;&#xff08;部署过程参考的下面红色字体文档链接就可以&#xff0c;步骤很详细&#xff0c;重点部分在下面做了标注&#xff09; 安装部署K8S集群文档&#xff1a; 使用kubeadm方式搭建K8S集群 GitBook 本机&#xff1a; master&#xff1a;10.0.0.13 maste…

pytorch 实现线性回归(深度学习)

一 查看原始函数 初始化 %matplotlib inline import random import torch from d2l import torch as d2l 1.1 生成原始数据 def synthetic_data(w, b, num_examples):x torch.normal(0, 1, (num_examples, len(w)))y torch.matmul(x, w) bprint(x:, x)print(y:, y)y tor…