Zookeeper 学习笔记

zookeeper 学习

第一章 Zookeeper 入门

概述

Zookeeper 是一个开源的分布式的,为分布式应用提供协调服务的 Apache 项目

设计模式:基于观察者模式设计的分布式服务管理框架

Zookeeper = 文件系统 + 通知机制

img

img

特点

  • Zookeeper:一个领导者(Leader),多个跟随者(follower)组成的集群
  • 集群中只要有半数以上节点存活,Zookeeper 集群就能正常提供服务
  • 全局数据一致:每个 Server 保存一份相同的数据副本,Client 无论连接到哪个 Server,数据都是一致的
  • 更新请求顺序进行,来自同一个 Client 的更新请求按其发送顺序依次执行
  • 数据更新原子性,一次数据更新要么成功,要么失败
  • 实时性,在一定时间范围内,Client 能读到最新数据

数据结构

Zookeeper 数据模型的结构与 Unix 文件系统很类似,整体上可以看做是一棵树,每个节点称作一个 ZNode。每个 ZNode 默认能够存储 1MB 的数据,每个 ZNode 都可以通过其唯一路径标识

img

应用场景

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

统一命名服务

分布式环境下,经常需要对应用/服务进行统一命名,便于识别(如域名相对IP)

image-20210330145527412

统一配置管理

  • 将配置信息写入 Zookeeper 上的一个 ZNode
  • 各个节点监听这个 ZNode
  • 一旦 ZNode 中数据被修改,Zookeeper 将通知各个节点

image-20210330145610967

统一集群管理

分布式环境中,实时掌握每个节点的状态

  • 将节点信息写入 Zookeeper 上的一个 ZNode
  • 监听这个 ZNode,可获取它的实时状态变化

image-20210330145453232

服务器动态上下线

客户端能实时洞察到服务器上下线的变化

image-20210330145652177

软负载均衡

在 Zookeeper 中记录每台服务器的访问数,让访问数最少的服务器去处理最新的客户端请求

image-20210330145942955

第二章 下载&安装

  • 安装 JDK
  • 下载 Zookeeper
  • 重命名 zoo_sample.cfg --> zoo.cfg
  • 修改配置 dataDir
  • 启动服务的&客户端

第三章 内部原理

选举机制

  • 半数机制:集群中半数以上机器存活,集群可用。所以 Zookeeper 适合安装基数台服务器
  • Zookeeper 没有在配置中指定 Master 和 Slave,但是,Zookeeper 工作时,一个节点为 Leader,其他则为 Follower,Leader 是通过内部的选举机制临时产生的

img

每个Zookeeper Server 先选自己,再选 id 比自己大的

节点类型

持久:客户端和服务器断开连接后,创建的节点不删除

  • 持久化目录节点:
  • 持久化顺序编号目录节点:

短暂:客户端和服务器断开连接后,创建的节点自己删除

  • 临时目录节点:
  • 临时顺序编号目录节点:

监听器原理

img

  • 监听节点数据的变化:get -w path
  • 监听子节点增减的变化:ls -w path

(1)在Zookeeper的API操作中,创建main()主方法即主线程;

(2)在main线程中创建Zookeeper客户端(zkClient),这时会创建两个线程:

  • 线程connet负责网络通信连接,连接服务器;

  • 线程Listener负责监听;

(3)客户端通过connet线程连接服务器;

  • 图中getChildren("/" , true) ," / "表示监听的是根目录,true表示监听,不监听用false

(4)在Zookeeper的注册监听列表中将注册的监听事件添加到列表中,表示这个服务器中的/path,即根目录这个路径被客户端监听了;

(5)一旦被监听的服务器根目录下,数据或路径发生改变,Zookeeper就会将这个消息发送给Listener线程;

(6)Listener线程内部调用process方法,采取相应的措施,例如更新服务器列表等。

第四章 常用命令

  • help:输出zk支持的所有命令
  • ls:查看指定路径下包含的节点
  • create:创建一个节点(-s 序号,-e 临时)
  • get:显示指定路径下节点的内容(-w 监听节点)
  • set:设置节点的内容
  • delete:删除一个节点

Stat 结构体

[zk: localhost:2181(CONNECTED) 22] get -s /sanguo/shuguo
zhugeliang
// 时间戳类型事务id
cZxid = 0x3
// znode 被创建的时间
ctime = Tue Mar 30 15:33:38 CST 2021
// znode 最后更新的事务 zxid
mZxid = 0x6
// znode最后修改的实际
mtime = Tue Mar 30 15:41:21 CST 2021
// znode 最后更新的子节点 zxid
pZxid = 0x3
// znode 子节点变化号,znode 子节点修改次数
cversion = 0
// znode 数据变化号
dataVersion = 1
// znode 访问控制表的变化号
aclVersion = 0
// 如果是临时节点,保存 znode 拥有者的 session id,如果不是则为 0
ephemeralOwner = 0x0
// znode 内容长度
dataLength = 10
// 子节点数量
numChildren = 0

第五章 基于 Java 的客户端实现

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.5.8</version>
        </dependency>
package com.wdg.zookeepersample;

import org.apache.log4j.Logger;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @description: Zookeeper客户端测试类
 * @author: WuDG/1490727316@qq.com
 * @date: 2021/3/30 16:15
 */
public class ZookeeperDemoTest {
    private static Logger LOG = Logger.getLogger(ZookeeperDemoTest.class);
    private static ZooKeeper zkClient = null;

    /**
     * 创建连接
     */
    @Before
    public void init(){
        LOG.info("Zookeeper 初始化解决启动");
        try {
            zkClient = new ZooKeeper("localhost:2181", 1000, new Watcher() {

                @Override
                public void process(WatchedEvent watchedEvent) {
                    LOG.info("watch 监听器回调触发");
                    try {
                        List<String> children = zkClient.getChildren("/", true);
                        children.forEach(LOG::info);
                        LOG.info("---------------------------");
                    } catch (KeeperException e) {
                        e.printStackTrace();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建节点
     */
    @Test
    public void create(){
        try {
            zkClient.create("/China", "JiangXi".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    /**
     * 获取子节点并监控数据变化
     * 监听子节点数据变化需要重写 ZooKeeper 构造方法里面的 Watch#process
     */
    @Test
    public void getDataAndwatch(){
        try {
//            List<String> children = zkClient.getChildren("/", false);
            List<String> children = zkClient.getChildren("/", true);
            children.forEach(LOG::info);
            TimeUnit.DAYS.sleep(1);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 判断节点是否存在
     */
    @Test
    public void exist(){
        try {
            Stat exists = zkClient.exists("/Nanchang", false);
            LOG.info(Objects.isNull(exists)?"节点不存在":exists);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×