Zookeeper的使用

发布时间:2024年01月22日

系列文章目录

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
Zookeeper的使用


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

在如今的数据驱动时代,分布式系统已经成为企业和组织处理大规模数据和提供高可靠性服务的重要手段。而 Zookeeper 作为一种分布式协调服务框架,在分布式系统中扮演着关键的角色。
Zookeeper 提供了一个简单而强大的机制来管理分布式应用程序的状态。它通过提供一个共享的注册表,使得分布式系统中的各个节点可以协调彼此的行为,实现一致性、可靠性和可伸缩性。
在这篇博客中,我将深入探讨 Zookeeper 的核心概念、功能和应用场景。我们将了解 Zookeeper 如何实现配置管理、命名服务等重要功能。我还将分享一些实际的使用案例,展示 Zookeeper 在大规模分布式系统中的优势和价值。
无论是你是分布式系统的开发者、架构师还是运维人员,了解和掌握 Zookeeper 的使用都是至关重要的。通过合理利用 Zookeeper,你将能够构建更加可靠、高效和可扩展的分布式应用。
让我们一起探索 Zookeeper 的世界,掌握其强大的功能,为你的分布式系统架构带来新的可能性!


提示:以下是本篇文章正文内容,下面案例可供参考

一、Zookeeper概述

Zookeeper 是一种开源的分布式协调服务框架,它提供了一个高性能、高可用的分布式数据管理和协调平台。Zookeeper 最初是由 Yahoo! 开发的,并于 2010 年成为 Apache 软件基金会的顶级项目。
Zookeeper 的设计目标是解决分布式应用程序中常见的协调问题,如服务发现、领导选举、配置管理、分布式锁等。它通过维护一个树形结构的目录来存储和管理分布式应用程序的状态信息。
Zookeeper 的核心特性包括:

  • 一致性:Zookeeper 保证了数据的一致性,即在多个节点之间的数据是一致的。
  • 可靠性:Zookeeper 通过冗余备份和容错机制,保证了系统的高可靠性。
  • 顺序性:Zookeeper 保证了客户端请求的顺序执行。
  • 高性能:Zookeeper 具有高效的数据存储和读取性能,能够支持大规模的分布式应用。

Zookeeper 通常以集群的形式部署,由多个节点组成,其中一个节点被选举为领导者(Leader),其他节点为追随者(Follower)。领导者负责处理客户端的请求,并将数据同步到追随者节点。
Zookeeper 被广泛应用于各种分布式系统中,如 Hadoop、Kafka、HBase 等。它为分布式应用程序提供了一个可靠的基础设施,使得开发和管理分布式系统变得更加简单和可靠。
如果你对 Zookeeper 感兴趣,我建议你进一步了解它的工作原理、应用场景和实际使用案例。通过深入学习,你将能够更好地利用 Zookeeper 来构建和管理高性能、可靠的分布式系统。

二、应用场景

  • 数据发布/订阅:Zookeeper 支持数据的发布/订阅模型,一方发布数据,多个订阅者可以实时获取数据的变更。
  • 分布式锁:在分布式系统中,多个进程或线程可能需要竞争共享资源。Zookeeper 可以提供分布式锁的实现,以确保资源的互斥访问。
  • 服务发现:在分布式系统中,服务通常以分布式的方式部署在多个节点上。Zookeeper 可以用于注册和发现服务,客户端通过 Zookeeper 获取可用的服务节点信息。
  • 命名服务:Zookeeper 可以作为一个全局的命名服务,用于给分布式系统中的资源或实体分配唯一的标识符。
  • 分布式协调/通知:分布式协调/通知服务是分布式系统中不可缺少的一个环节,是将不同的分布式组件有机结合起来的关键所在。对于一个在多台机器上部署运行的应用而言,通常需要一个协调者(Coordinator)来控制整个系统的运行流程。

三、Zookeeper的基本概念

  • 集群角色:通常在分布式系统中,构成一个集群的每一台机器都有自己的角色,最典型的集群模式就是Master/Slave模式(主备模式)。通常在分布式系统中,构成一个集群的每一台机器都有自己的角色,最典型的集群模式就是Master/Slave模式(主备模式)。
  • 数据节点(znode):Zookeeper 中的数据节点称为 Znode,它是 Zookeeper 中存储数据的基本单位。Znode 可以包含数据、子节点以及元数据(如版本号、创建时间等)。
  • 监听(Watcher):Zookeeper 支持监听机制。客户端可以注册对 Znode 的监听,当 Znode 发生变化(如数据更新、子节点创建/删除等)时,客户端会收到通知。
  • ACL:Zookeeper 提供访问控制列表(ACL)来控制对 Znode 的访问权限。ACL 可以定义不同的权限,如只读、读写、完全控制等。

注意:Zookeeper=文件系统+监听机制

四、Zookeeper安装

Zookeeper伪集群安装

1.下载Zookeeper压缩包点击这里
2.解压zookeeper

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

3.修改配置文件,进入zookeeper的安装目录的conf目录

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

4.修改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

5.创建数据持久化目录

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

6.配置JDK环境,vim /etc/profile

export JAVA_HOME=/usr/local/jdk
export PATH=$PATH:$JAVA_HOME/bin

7.生效环境变量

source /etc/profile

8.启动zookeeper服务

zkServer.sh start

9.查看Zookeeper运行状态

zkServer.sh status

集群安装

1.环境准备

服务器1  192.168.66.101
服务器2  192.168.66.102
服务器3  192.168.66.103

2.解压zookeeper

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

3.修改配置文件,进入zookeeper的安装目录的conf目录

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

4.修改zoo.cfg

# 心跳检查的时间 2秒
tickTime=2000initLimit=10
# ZK Leader 和follower 之间通讯的次数,总时间5*2=10秒
syncLimit=5
# 存储内存中数据快照的位置,如果不设置参数,更新事务日志将被存储到默认位置。
dataDir=/usr/local/zookeeper/zkdata
# ZK 服务器端的监听端口 
clientPort=2181


#autopurge.purgeInterval=1
server.1=192.168.66.101:2888:3888
server.2=192.168.66.102:2888:3888
server.3=192.168.66.103:2888:3888

5.创建数据持久化目录,对3台节点,都创建zkdata目录 。

mkdir /usr/local/zookeeper/zkdata

7.在工作目录中生成myid文件

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

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

bin/zkServer.sh start

五、Zookeeper系统模型

在Zookeeper中,可以说 Zookeeper中的所有存储的数据是由znode组成的,节点也称为 znode,并以 key/value 形式存储数据。以 key/value 形式存储数据。key就是znode的节点路径,比如 /java , /server。

znode节点类型

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

持久节点

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

/java  spring
/zhangsan  zhangsan

持久顺序节点

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

/java00000000000001  spring
/baizhan00000000000001  itbaizhan

临时节点

从名称上可以看出该节点的一个最重要的特性就是临时性。所谓临时性是指,如果将节点创建为临时节点,那么该节点数据不会一直存储在 ZooKeeper 服务器上。
注意:和持久节点不同的是,临时节点的生命周期和客户端会话绑定。也就是说,如果客户端会话失效,那么这个节点就会自动被清除掉。注意,这里提到的是会话失效,而非连接断开。另外,在临时节点下面不能创建子节点。

临时顺序节点

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

/baizhan0000000000000001  zhangsan
/baizhan0000000000000002  zhangsan
/baizhan0000000000000003  zhangsan

六、客户端命令

创建

创建ZK节点,语法结构:

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

示例:

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

读取

读取节点信息ls命令和get命令,ls命令是显示节点下有哪些子节点,而get命令是查看具体节点的数据。

ls

语法结构:

ls path [watch]

示例;

ls /

get

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

get path [watch]

示例:

get /zk-book

更新

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

set path data [version]

删除

删除zookeeper上的指定节点。
语法结构:

delete path [version]

示例:

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

七、Watcher监听机制

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

监听机制

监听节点变化

语法结构:ls -w path

监听节点的值的变化

语法结构:get -w path

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

八、ACL权限控制

Zookeeper 中的 ACL(访问控制列表)用于控制对 Znode 节点的访问权限。它可以定义不同的权限,如读、写、完全控制等。ACL 可以设置到 Znode 节点上,这样只有具有相应权限的客户端才能访问该节点。
语法格式:setAcl path Schema:ID:Permission

  • Schema:权限模式
  • ID:授权对象
  • Permission:权限

Schema可选参数如下:

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

ID可选参数如下:

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

Permission可选参数如下:

项目Value
c可以创建子节点
d可以删除子节点(仅下一级节点)
r可以读取节点数据及显示子节点列表
w可以设置节点数据
a可以设置节点访问控制列表权限

权限相关语法/命令:

命令注释
getAcl读取ACL权限
setAcl设置ACL权限
addauth添加认证用户

实战

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>
示例:

#创建节点
[zk: localhost:2181(CONNECTED) 0] create /node2 1
Created /node2
#设置权限
[zk: localhost:2181(CONNECTED) 1] setAcl /node2 ip:192.168.100.1:cdrwa #设置IP:192.168.66.101 拥有所有权限
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>
示例:
1.添加认证用户

addauth digest <user>:<password>

2.授权

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

Digest方案

语法结构:setAcl <path> digest:<user>:<password>:<acl>

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

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

2.先来计算一个密文

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

3.授权

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

Java操作Zookeeper

原生api操作Zookeeper

引入依赖

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

创建会话

 /**
     * 创建一个 Zookeeper 的实例
     * 此处为一个集群,Zookeeper 的 ip 之间用逗号隔开
     *
     * 参数解释:
     * param 1 - Zookeeper 的实例 ip ,此处是一个集群,所以配置了多个 ip,用逗号隔开
     * param 2 - session 过期时间,单位秒 (1000)
     * param 3 - 监视者,用于获取监听事件 (MyWatch)
     */
ZooKeeper zooKeeper = new ZooKeeper("192.168.1.108:2181", 5000, watcher);

创建节点

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的四种类型:

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

删除节点

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

更新数据

/*
*znode名称
*节点数据
*该节点的版本
*/
Stat stat = zooKeeper.setData("/poype_node2", "poype5211314".getBytes(), 1);

检测节点是否存在

private void existSync() throws KeeperException, InterruptedException {
/*
*znode 名称 (/zoo)
*监视者,用于获取监控事件 (MyWatch)
*/
   Stat stat = zooKeeper.exists("/poype_node2", true);
   System.out.println(stat);
}

注册监听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);
    }   
}



注册监听事件getDate

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);
    }
}



zkclient库操作Zookeeper

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.101:2181";
ZkClient zk = new ZkClient(connStr);

创建节点

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

修改节点数据

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

获取节点数据

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);
       });
     });


总结

提示:这里对文章进行总结:

例如:以上就是今天要讲的内容,本文仅仅简单介绍了Zookeeper的使用,如果大家有什么疑问可以在评论区提出。

文章来源:https://blog.csdn.net/liubopro666/article/details/135751344
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。