zookeeper的简单学习

1. 基本概念

官方文档:https://zookeeper.apache.org/doc/r3.6.3/zookeeperStarted.html

官方文档上这么解释zookeeper,它是一个分布式服务框架,是Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。

上面的解释有点抽象,简单来说zookeeper=文件系统+监听通知机制。

Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架, 它负责存储和管理大家都关心的数据, 然后接受观察者的注册, 一旦这些数据的状态发生变化 ,Zookeeper就将负责通知已经在Zookeeper上注册的那些观察者做出相应的反应。

  • Zookeeper 可以被用作注册中心。
  • Zookeeper 是 Hadoop 生态系统的一员。
  • 构建 Zookeeper 集群的时候,使用的服务器最好是奇数台。

ZooKeeper 是一个典型的分布式数据一致性解决方案,分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅负载均衡命名服务分布式协调/通知集群管理Master 选举、分布式锁分布式队列等功能。

1.1 文件系统

Zookeeper维护一个类似文件系统的数据结构。文件树存储在内存中,所以速度很快。

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

每个子目录项如 NameService 都被称作为 znode(目录节点),和文件系统一样,我们能够自由的增加、删除znode,在一个znode下增加、删除子znode,唯一的不同在于znode是可以存储数据的。

有四种类型的znode:

  • PERSISTENT-持久化目录节点

    客户端与zookeeper断开连接后,该节点依旧存在

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

    客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号

  • EPHEMERAL-临时目录节点

    客户端与zookeeper断开连接后(会话失效,超时后失效,或者会话执行quit),该节点被删除

  • EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点

    客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号

1.2 特点

在这里插入图片描述

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

2. 安装

2.1 源码包安装

我学习时的稳定版本为3.6.3,前置条件已安装jdk

1.下载地址:https://ftp.wayne.edu/apache/zookeeper/zookeeper-3.6.3/apache-zookeeper-3.6.3-bin.tar.g
在这里插入图片描述

2.将安装包copy到linux的指定文件夹下。

3.解压到自定义目录。

tar -xvzf 压缩文件

4.修改配置文件

将conf文件夹下的zoo-simple.cfg文件修改为zoo.cfg

# cp conf/zoo_sample.cfg conf/zoo.cfg

5.启动

# bin/zkServer.sh start (配置文件路径)

6.jps查看是否启动

huodada@huodada:~/software/zookeeper/apache-zookeeper-3.6.3-bin$ jps

1657730 QuorumPeerMain  --说明启动乘公共
2532090 ZooKeeperMain

7.启动客户端

bin/zkCli.sh #默认连接本地服务器

# 连接启动服务器使用-server参数
bin/zkCli.sh -server 127.0.0.1:2181

##
quit  #关闭连接并使会话失效

8.停止

bin/zkServer.sh stop

2.2 docker安装

比较简单,下载3.6的镜像启动即可。

3. 配置文件

Zookeeper中的配置文件zoo.cfg中参数含义解读如下:
1. tickTime =2000: 通信心跳数, Zookeeper 服务器与客户端心跳时间,单位毫秒
Zookeeper使用的基本时间,服务器之间或客户端与服务器之间维持心跳的时间间隔,
也就是每个tickTime时间就会发送一个心跳, 时间单位为毫秒。
它用于心跳机制,并且设置最小的session超时时间为两倍心跳时间。 (session的最小超
时时间是2*tickTime)

2. initLimit =10: LF 初始通信时限,也就是初始化集群时集群节点同步超时事件为20s
集群中的Follower跟随者服务器与Leader领导者服务器之间初始连接时能容忍的最多心
跳数(tickTime的数量),用它来限定集群中的Zookeeper服务器连接到Leader的时限。

3. syncLimit =5: LF 同步通信时限
集群中Leader与Follower之间的最大响应时间单位,假如响应超过syncLimit *
tickTime, Leader认为Follwer死掉,从服务器列表中删除Follwer。

4. dataDir:数据文件目录+数据持久化路径
主要用于保存 Zookeeper 中的数据。

5. clientPort =2181:客户端连接端口
监听客户端连接的端口。

4. 客户端基本命令

zookeeper的api命令比较简单,在 shell 中,键入 help 以获得可以从客户端执行的命令列表,共有以下命名。

ZooKeeper -server host:port -client-configuration properties-file cmd args
        addWatch [-m mode] path # optional mode is one of [PERSISTENT, PERSISTENT_RECURSIVE] - default is PERSISTENT_RECURSIVE
        addauth scheme auth
        close 
        config [-c] [-w] [-s]
        connect host:port
        create [-s] [-e] [-c] [-t ttl] path [data] [acl]
        ## -s表示创建顺序节点,-e表示临时节点,默认为永久节点
        delete [-v version] path
        deleteall path [-b batch size]
        delquota [-n|-b] path
        get [-s] [-w] path
        getAcl [-s] path
        getAllChildrenNumber path
        getEphemerals path
        history 
        listquota path
        ls [-s] [-w] [-R] path
        printwatches on|off
        quit 
        reconfig [-s] [-v version] [[-file path] | [-members serverID=host:port1:port2;port3[,...]*]] | [-add serverId=host:port1:port2;port3[,...]]* [-remove serverId[,...]*]
        redo cmdno
        removewatches path [-c|-d|-a] [-l]
        set [-s] [-v version] path data
        setAcl [-s] [-v version] [-R] path acl
        setquota -n|-b val path
        stat [-w] path
        sync path
        version 

说明:

ZooKeeper 的设计目标之一是提供一个非常简单的编程接口。因此,它只支持以下操作:

create : creates a node at a location in the tree 》》create /zk_test my_data

Create: 在树中的某个位置创建一个节点

delete : deletes a node  》》delete /zk_test

删除: 删除节点

exists : tests if a node exists at a location

如果一个节点在某个位置存在,则测试

get data : reads the data from a node 》》get /zk_test

获取数据: 从一个节点读取数据

set data : writes data to a node

Set data: 设置某个节点的数据 》》set /zk_test junk

get children : retrieves a list of children of a node

Get children: 检索节点的子节点列表

ls path  》》 ls /

sync : waits for dat

6. 节点监听机制

zookeeper支持监听功能,当监听的节点或者节点数据发生变化时,执行一次监听语句,只发生一次监听回调。

监听节点数据:get [-s] [-w] path 》》当一个客户端

监听节点:ls [-w] path

7. java操作ZK

可以使用java或者c来当做客户端。

详细文档参见https://zookeeper.apache.org/doc/r3.6.3/zookeeperProgrammers.html#ch_programStructureWithExample

java使用的依赖为

    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.6.3</version>
    </dependency>

下面是测试代码

package com.huo.test;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Id;
import org.apache.zookeeper.data.Stat;
import org.apache.zookeeper.proto.WatcherEvent;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.omg.CORBA.ARG_OUT;

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

/**
 * package: com.huo.test
 * author: Huo
 * Description:
 * Date: Create in 13:17 2021/4/23
 */
public class Demo02 implements Watcher {
    private ZooKeeper zooKeeperClient;
    private static final String IP = "192.168.1.101:2181";
    private static final int SESSION_OUTTIME = 5000;
    //用于阻塞程序执行,直到zk成功连接后再发送继续执行信号,因为zk建立连接是异步的,阻塞是防止程序在zk成功连接前被调用。
    private static final CountDownLatch contectedSemaphore = new CountDownLatch(1);


    @Override
    public void process(WatchedEvent event) {
        //WatcherEvent为观察者监听事件

        //获取事件状态(与客户端连接状态相关)
        /*
         * KeeperState:Disconneced        连接失败
         * KeeperState:SyncConnected	 连接成功
         * KeeperState:AuthFailed         认证失败
         * KeeperState:Expired            会话过期
         */
        Event.KeeperState state = event.getState();

        //获取事件类型(与zknode相关)
        /*
         * EventType:NodeCreated            节点创建
         * EventType:NodeDataChanged        节点的数据变更
         * EventType:NodeChildrentChanged   子节点下的数据变更
         * EventType:NodeDeleted            节点删除
         * EventType:None                   刚连接什么都没做
         */
        Event.EventType type = event.getType();
        System.out.println(type);

        //成功建立连接(固定写法)
        //发送信号让程序继续执行
        //成功建立连接(固定写法)
        if (Event.KeeperState.SyncConnected == state) {
            if (Event.EventType.None == type) {
                //发送信号让程序继续执行
                contectedSemaphore.countDown();
            }
        }
    }

    //创建节点
    @Test
    public void testCreateNode() throws InterruptedException, KeeperException {
        System.out.println(zooKeeperClient);
        //阻塞程序执行
        String newNode = zooKeeperClient.create("/huonode", "huodalao".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        System.out.println("创建节点" + newNode);
    }

    //获取某个路径的所有子节点
    @Test
    public void getAllNode() throws InterruptedException, KeeperException {
        System.out.println(zooKeeperClient);
        //阻塞程序执行
        List<String> newNode = zooKeeperClient.getChildren("/", false);
        System.out.println("该路径下所有子节点" + newNode);
    }

    /**
     * 获取节点上面的数据
     *
     * @param
     * @return
     * @throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void getData() throws KeeperException, InterruptedException {
        byte[] data = zooKeeperClient.getData("/node", false, null);
        if (data == null) {
            System.out.println("null");;
        }
        System.out.println(new String(data));
    }

    /**
     * 设置节点信息
     *
     * @return
     * @throws InterruptedException
     */
    @Test
    public void setData() throws KeeperException, InterruptedException {
        Stat stat = zooKeeperClient.setData("/node", "huodada".getBytes(), -1);
        System.out.println(stat);
        this.getData();
    }

    /**
     * 删除节点
     *
     * @throws InterruptedException
     * @throws KeeperException
     */
    @Test
    public void deleteNode() throws InterruptedException, KeeperException {
        zooKeeperClient.delete("/testRoot", -1);
    }

    /**
     * 获取创建时间
     *
     * @return
     * @throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void getCTime() throws KeeperException, InterruptedException {
        Stat stat = zooKeeperClient.exists("/node", false);
        System.out.println(String.valueOf(stat.getCtime()));
    }

    /**
     * 获取某个路径下孩子的数量
     *
     * @return
     * @throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void getChildrenNum() throws KeeperException, InterruptedException {
        int childenNum = zooKeeperClient.getChildren("/", false).size();
        System.out.println(childenNum);
    }
	//启动某个事件之前先创建链接对象
    @Before
    public void getConnect() throws IOException, InterruptedException {
        zooKeeperClient = new ZooKeeper(IP, 6000 * 30, this);
        //保证连接创建成功
        contectedSemaphore.await();
        System.out.println("zookeeper connection success");
    }

    //完成处理后关闭连接
    @After
    public void closeClient() throws InterruptedException {
        zooKeeperClient.close();
    }


}

8. ZK的集群

在独立模式下运行 ZooKeeper 方便了评估、开发和测试。但是在生产环境中,应该以复制模式运行 ZooKeeper。同一应用程序中的复制服务器组称为仲裁,在复制模式下,仲裁中的所有服务器都具有相同配置文件的副本。

至少需要三台服务器,并且强烈建议您使用奇数个服务器。

配置文件示例

tickTime=2000 # 毫秒
dataDir=/var/lib/zookeeper #数据目录
clientPort=2181
initLimit=5  #五个tickTime
syncLimit=2  #两个tickTime
server.1=zoo1的ip:2888:3888 
server.2=zoo2的ip:2888:3888
server.3=zoo3的ip:2888:3888

说明:主要是最后三行,各主机都需要包括本身所有主机的ip和两个端口。

server.X 的条目列出了组成 ZooKeeper 服务的服务器。当服务器启动时,它通过在数据目录中查找文件 myid 来知道它是哪个服务器。也就是说每个zookeeper服务器的数据目录都有一个myid文件里面有一个整形数字标识服务器号。

2888:各主机之间的同步,3888:心跳检查

然后三台服务器做同样的配置,启动后会产生一个leader两个follower。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值