Zookeeper 学习笔记 (详细)

Posted 黑桃️

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Zookeeper 学习笔记 (详细)相关的知识,希望对你有一定的参考价值。


一、Zookeeper 入门

(1) 概述

Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目。Zookeeper工作机制如下:
在这里插入图片描述

(2) 特点

在这里插入图片描述

(3) 数据结构

在这里插入图片描述

(4) 应用场景

提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡 等。

统一命名服务
在这里插入图片描述
统一配置服务
在这里插入图片描述
统一集群管理
在这里插入图片描述

服务器节点动态上下线
在这里插入图片描述

软负载均衡
在这里插入图片描述

(5) 下载地址

官网


二、Zookeeper 安装

(1) 本地模式安装部署

① 安装前准备

安装Jdk
在这里插入图片描述

拷贝Zookeeper安装包到Linux系统下

解压:tar -zxvf 压缩包名 目录   (解压到指定目录,不加目录默认当前目录)

在这里插入图片描述

② 配置修改

将/opt/zookeeper-3.4.10/conf这个路径下的zoo_sample.cfg修改为zoo.cfg;

mv zoo_sample.cfg zoo.cfg

在这里插入图片描述

打开zoo.cfg文件,修改dataDir路径:

需要手动创建 dataDir路径
在这里插入图片描述

在这里插入图片描述

③ 操作Zookeeper

在这里插入图片描述

启动Zookeeper

bin/zkServer.sh start

在这里插入图片描述

查看进程是否启动

jps

在这里插入图片描述

查看状态:

bin/zkServer.sh status

在这里插入图片描述

启动客户端:

bin/zkCli.sh

在这里插入图片描述
在这里插入图片描述

退出客户端:

quit

在这里插入图片描述

停止Zookeeper

bin/zkServer.sh stop

在这里插入图片描述

(2) 配置参数解读

在这里插入图片描述


三、Zookeeper 内部原理

(1) 选举机制 (★)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(2) 节点类型

在这里插入图片描述

(3) Stat 结构体

在这里插入图片描述

(4) 监听器原理 (★)

在这里插入图片描述

(5) 写数据流程

在这里插入图片描述


四、Zookeeper 实战 (★)

🔺 分布式安装部署

在一台机器上模拟3个 zk server的集群安装

前提:解压后zookeeper后,新建三个zkData,然后在conf中将zoo_sample.cfg改名,复制三份zoo配置文件
在这里插入图片描述
在这里插入图片描述

(1) 配置服务器编号

在 zkData 文件夹下创建myid文件,内容分别为id值1,2,3

在这里插入图片描述

(2) 配置 zoo.cfg 文件

server.1=192.168.44.129:2887:3887
server.2=192.168.44.129:2888:3888
server.3=192.168.44.129:2889:3889

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

配置参数解读:server.A=B:C:D。

在这里插入图片描述

(3) 集群操作

分别启动Zookeeper

# 启动服务端
bin/zkServer.sh start conf/zoo1.cfg

# 启动对应服务端的客户端
bin/zkCli.sh -server localhost:2182

在这里插入图片描述

查看状态
( 根据之前的投票规则:正常情况下应该是 zookeeper-2 是 leader,1,3为follower )

bin/zkServer.sh status conf/zoo1.cfg 

在这里插入图片描述


🔺 客户端命令行操作

在这里插入图片描述

(1) 启动客户端

bin/zkCli.sh

bin/zkCli.sh -server localhost:2182 #指定某台server的客户端

在这里插入图片描述
在这里插入图片描述

(2) 显示所有操作命令

在这里插入图片描述

(3) 查看当前znode中所包含的内容

在这里插入图片描述

(4) 查看当前节点详细数据

在这里插入图片描述

(5) 分别创建2个普通节点

在这里插入图片描述

(6) 获得节点的值

在这里插入图片描述

在这里插入图片描述

(7) 创建短暂节点

在这里插入图片描述
在这里插入图片描述

(8) 创建带序号的节点

在这里插入图片描述

(9) 修改节点数据值

在这里插入图片描述

(10) 节点的值变化监听

在这里插入图片描述

(11) 节点的子节点变化监听(路径变化)

在这里插入图片描述

(12) 删除节点

在这里插入图片描述

(13) 递归删除节点

在这里插入图片描述

(14) 查看节点状态

在这里插入图片描述


🔺 API 应用

(1) 创建一个 maven 工程

在这里插入图片描述

(2) 添加 pom 文件

<dependencies>
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>RELEASE</version>
	</dependency>
	<dependency>
		<groupId>org.apache.logging.log4j</groupId>
		<artifactId>log4j-core</artifactId>
		<version>2.8.2</version>
	</dependency>
	<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
	<dependency>
		<groupId>org.apache.zookeeper</groupId>
		<artifactId>zookeeper</artifactId>
		<version>3.4.10</version>
	</dependency>
</dependencies>

(3) 拷贝log4j.properties文件到项目根目录

需要在项目的src/main/resources目录下,新建一个文件命名为“log4j.properties”,在文件中填入。
在这里插入图片描述

log4j.rootLogger=INFO, stdout  
log4j.appender.stdout=org.apache.log4j.ConsoleAppender  
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout  
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n  
log4j.appender.logfile=org.apache.log4j.FileAppender  
log4j.appender.logfile.File=target/spring.log  
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout  
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n  

(4) 创建ZooKeeper客户端

// 创建ZooKeeper客户端,客户端连接服务端
public static void init() throws IOException {
    zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
        @Override
        public void process(WatchedEvent watchedEvent) {
        }
    });
}
public static void main(String[] args) throws Exception {
    init();
}

在这里插入图片描述

(5) 创建子节点

如果是远程连接操作的虚拟机中的zk,一定要记得:

关闭 linux 环境中的防火墙!
关闭 linux 环境中的防火墙!
关闭 linux 环境中的防火墙!
在这里插入图片描述

// 创建子节点
public static void create() throws Exception {

    // 参数1:要创建的节点的路径
    String path = "/testCreate";

    // 参数2:节点数据
    byte[] data = "ht".getBytes();

    // 参数3:节点权限
    List<ACL> acls = Ids.OPEN_ACL_UNSAFE;

    // 参数4:节点的类型
    CreateMode createMode = CreateMode.PERSISTENT;

    String nodeCreated = zkClient.create(path, data, acls, createMode);

    System.out.println(nodeCreated);
}
public static void main(String[] args) throws Exception {
    init();
    create();
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(6) 获取子节点并监听节点变化

获取节点

public static void getDataAndWatch() throws KeeperException, InterruptedException {

    List<String> children = zkClient.getChildren("/", true);

    for (String child : children) {
        System.out.println(child);
    }

    // 延时阻塞
    Thread.sleep(Long.MAX_VALUE);
}
// 创建ZooKeeper客户端,客户端连接服务端
public static void init() throws IOException {
    zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
        // 监听
        @Override
        public void process(WatchedEvent watchedEvent) {
            List<String> children = null;
            System.out.println("---------start---------");
            try {

                children = zkClient.getChildren("/", true);

                for (String child : children) {
                    System.out.println(child);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("---------end---------");
        }
    });
}
public static void main(String[] args) throws Exception {
    init();
//  create();
    getDataAndWatch();
}

在这里插入图片描述
在这里插入图片描述

(7) 判断Znode是否存在

// 判断节点是否存在
public static void isExist() throws KeeperException, InterruptedException {

    Stat exists = zkClient.exists("/sanguo", false);

    System.out.println(exists==null ? "not exist" : "exist");
}
public static void main(String[] args) throws Exception {
    init();
//  create();
//  getDataAndWatch();
    isExist();
}

在这里插入图片描述


🔺 监听服务器节点动态上下线案例

(1) 需求

某分布式系统中,主节点可以有多台,可以动态上下线,任意一台客户端都能实时感知到主节点服务器的上下线

(2) 需求分析

在这里插入图片描述

(3) 具体实现

① 先在集群上创建/servers节点

create /servers "servers"

在这里插入图片描述

② 服务器端向Zookeeper注册代码

public class DistributeServer {

    private String connectString = "192.168.44.129:2181,192.168.44.129:2182,192.168.44.129:2183";
    private int sessionTimeout =  10000;
    private ZooKeeper zk = null;
    private String parentNode = "/servers";
    private static String hostname = "ht";

    public static void main(String[] args) throws Exception {

        DistributeServer server = new DistributeServer();

        // 服务端获取和zk的连接
        server.getConnect();

        // 注册服务器
        server.registServer(hostname);

        // 业务逻辑
        server.businesss(hostname);
    }

    // 注册服务器
    public void registServer(String hostname) throws Exception{

        String create = zk.create(parentNode + "/server", hostname.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);

        System.out.println(hostname +" is online "+ create);
    }


    // 业务逻辑代码
    private void businesss(String hostname) throws InterruptedException {

        System.out.println(hostname+" is working ...");

        // 延时阻塞
        Thread.sleep(Long.MAX_VALUE);
    }

    // 创建到zookeeper的客户端连接
    private void getConnect() throws IOException {

        zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {

            }
        });
    }
    
}

③ 客户端代码

public class DistributeClient {
    private String connectString = "192.168.44.129:2181,192.168.44.129:2182,192.168.44.129:2183";
    private int sessionTimeout =  10000;
    private ZooKeeper zk = null;
    private String parentNode = "/servers";

    public static void main(String[] args) throws Exception {
        DistributeClient client = new DistributeClient();

        // 1获取zk连接
        client.getConnect();

        // 2获取servers的子节点信息,从中获取服务器信息列表
        client.getServerList();

        // 3业务进程启动
        client.business();
    }

    // 3业务进程启动
    private void business() throws InterruptedException {

        System.out.println("client is working ...");

        Thread.sleep(Long.MAX_VALUE);
    }

    private void getServerList() throws KeeperException, InterruptedException {

        // 1获取服务器子节点信息,并且对父节点进行监听
        List<String> children = zk.getChildren(parentNode, true);

        // 2存储服务器信息列表
        ArrayList<String> servers = new ArrayList<>();

        // 3遍历所有节点,获取节点中的主机名称信息
        for (String child : children) {

//            byte[] data = zk.getData(parentNode + "/" + child, false, null);
//
//            servers.add(new String(data));

            servers.add(child);
        }

        // 4 打印服务器列表的信息
        System.out.println(servers);
    }

    // 创建客户端和zookeeper的连接
    private void getConnect() throws IOException {
        zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                // 再次启动监听
                try {
                    getServerList();
                } catch (Exception e) {
                    e.printStackTrace以上是关于Zookeeper 学习笔记 (详细)的主要内容,如果未能解决你的问题,请参考以下文章

ZooKeeper源码学习笔记--Cluster模式下的ZooKeeper

zookeeper学习笔记

学习笔记:python3,代码片段(2017)

ZooKeeper学习笔记二:API基本使用

Kafka 学习笔记之 ZooKeeper作用

ZooKeeper学习笔记一:集群搭建