Zookeeper 学习笔记 (详细)

Posted 黑桃️

tags:

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

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学习笔记

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

Kafka 学习笔记之 ZooKeeper作用

ZooKeeper学习笔记一:集群搭建

深入了解Zookeeper核心原理