Zookeeper搭建集群及基本使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xudusuixin/article/details/79973388

1. zookeeper简介

Zookeeper是一个分布式协调服务, 是为用户的分布式应用程序提供协调服务
- Zookeeper是为别的分布式程序服务的
- Zookeeper本身就是一个分布式程序(只要有半数以上节点存活,zk就能正常服务)
- Zookeeper所提供的服务涵盖:主从协调、服务器节点动态上下线、统一配置管理、分布式共享锁、统一名称服务……
- 虽然说可以提供各种服务,但是zookeeper在底层其实只提供了两个功能:
管理(存储,读取)用户程序提交的数据;
并为用户程序提供数据节点监听服务;

2. zookeeper安装配置及集群搭建

2.1 下载 –> 官网
2.2 上传到linux后,解压
2.3 进入zookeeper目录,其根目录下几个目录如下
bin目录: 一些操作zookeeper的指令

zkServer.sh [start | stop | status | restart ]

conf目录: 配置文件

# 将conf目录下的 zoo_sample.cfg 复制一份为 zoo.cfg , zookeeper服务器启动默认加载zoo.cfg
cp  ./conf/zoo_sample.cfg  ./zoo.cfg

# 修改zoo.cfg中的配置, 修改内容如下
dataDir=/root/work/zookeeper/data     #  配置数据目录,创建一个data目录,将其路径填入即可
dataLogDir=/root/work/zookeeper/log   # 同理(可以不配置此项)
# 配置集群节点,server.x中 x 为节点id, slave1 为节点服务器主机名,或者ip地址
# 节点id配置, 在data目录下创建文件名为myid的文件,在文件中直接写入id即可,例如 slave1的myid文件中写   1  
server.1=slave1:2888:3888 (主机名, 心跳端口、数据端口)
server.2=slave2:2888:3888
server.3=slave3:2888:3888

zookeeper集群机制为半数机制, 即集群中半数以上机器存活集群才可用。

启动集群,把每个节点的zookeeper
zkServer.sh start
查看状态, 主从信息
zkServer.sh status

3. zookeeper 结构命令

3.1 zookeeper 特性

1、Zookeeper:一个leader,多个follower组成的集群
2、全局数据一致:每个server保存一份相同的数据副本,client无论连接到哪个server,数据都是一致的
3、分布式读写,更新请求转发,由leader实施
4、更新请求顺序进行,来自同一个client的更新请求按其发送顺序依次执行
5、数据更新原子性,一次数据更新要么成功,要么失败
6、实时性,在一定时间范围内,client能读到最新数据

3.2 zookeeper 数据结构

1、层次化的目录结构,命名符合常规文件系统规范(见下图)
znode
2、每个节点在zookeeper中叫做znode,并且其有一个唯一的路径标识
3、节点Znode可以包含数据和子节点(但是EPHEMERAL类型的节点不能有子节点)
4、客户端应用可以在节点上设置监视器

3.3 zookeeper节点类型

1、Znode有两种类型:

短暂(ephemeral)(断开连接自己删除)
持久(persistent)(断开连接不删除)

2、Znode有四种形式的目录节点(默认是persistent )

PERSISTENT
PERSISTENT_SEQUENTIAL(持久序列,例如 create -s /test 生成znode为 /test0000000001 )
EPHEMERAL
EPHEMERAL_SEQUENTIAL

3、创建znode时设置顺序标识,znode名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护
4、在分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序

3.4 znode节点元数据stat,例子

cZxid = 0xb00000003    内部数据更新时的事务控制的编号,创建一个数据时,内部就会有一个事务编号
ctime = Tue Feb 13 08:32:40 CST 2018  创建时间
mZxid = 0xb00000005  修改事务的编号
mtime = Tue Feb 13 08:34:47 CST 2018 修改时间
pZxid = 0xb00000003 持久化事务编号
cversion = 0 创建版本号
dataVersion = 1 数据版本号
aclVersion = 0  权限版本
ephemeralOwner = 0x0
dataLength = 5 数据长度
numChildren = 0  子节点数

3.5zookeeper 命令行操作

运行 zkCli.sh –server 进入命令行工具

[zk: localhost:2181(CONNECTED) 0] help    # help 指令查看帮助
ZooKeeper -server host:port cmd args  
    connect host:port    # 连接到zookeeper集群中其他节点
    get path [watch]     #  获取 path 的数据, wath (只监听一次)选项,监听 znode 数据变化
    ls path [watch]        #  获取 path 下的 znode 列表
    set path data [version]  # 修改 path 下znode的data
    rmr path                 #  递归删除 path 节点及其子节点
    delquota [-n|-b] path
    quit                       # 退出 zookeeper 客户端
    printwatches on|off
    create [-s] [-e] path data acl  # 创建节点, -s 设置顺序标识  -e 创建节点为短暂类型   acl 权限
    stat path [watch]    # 查看 path 的元数据
    close 
    ls2 path [watch]
    history 
    listquota path
    setAcl path acl
    getAcl path
    sync path
    redo cmdno
    addauth scheme auth
    delete path [version]   # 删除path节点,只能用于删除叶子节点
    setquota -n|-b val path

4. java操作zookeeper客户端

4.1 搭建环境

  • 方法一: 建立一个maven项目,在pom.xml中添加zookeeper客户端依赖
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.10</version>
</dependency>
  • 方法二: 建立一个普通的java项目,创建一个lib目录, 将zookeeper解压后的根目录下的 zookeeper-3.4.10.jar 和 根目录下的lib目录下的jar包一起拷贝到java项目的lib目录下,并将他们导入到项目环境中。

4.2 基本使用

org.apache.zookeeper.Zookeeper是客户端入口主类,负责建立与server的会话
它提供了表 1 所示几类主要方法 :

功能 描述
create 在本地目录树中创建一个节点
delete 删除一个节点
exists 测试本地是否存在目标节点
get/set data 从目标节点上读取 / 写数据
get/set ACL 获取 / 设置目标节点访问控制列表信息
get children 检索一个子节点上的列表
sync 等待要被传送的数据

4.2.1 基本操作,增删改查

package com.lunarku.bigdata.zk;

import java.util.List;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.junit.Before;
import org.junit.Test;

/**
 * java代码操作zookeeper测试
 */
public class SimpleZkClient {

    // zookeeper集群服务器ip端口
    private static final String CONNECT_STRING=
            "192.168.25.141:2181,192.168.25.142:2181,192.168.25.143:2181";
    private static final int SESSION_TIMEOUT = 2000;
    // 用来测试创建 /eclipse 节点
    private static final String PATH = "/eclipse";
    public ZooKeeper zkClient = null; 

    /**
     * 初始化 Zookeeper 对象
     * @throws Exception
     */
    @Before
    public void init() throws Exception {
        // 第三个参数为回调函数
        zkClient = new ZooKeeper(CONNECT_STRING, SESSION_TIMEOUT, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                // 收到事件通知后的回调函数
                System.out.println(event.getType() + "---" + event.getPath());
            }
        });
    } 

    /**
     * 创建 znode
     * @throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void testCreate() throws KeeperException, InterruptedException {
        // 参数1: 要创建的节点的路径 参数2: 节点数据  参数3: 节点权限  参数4:节点的类型
        zkClient.create(PATH, "zk-test".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        zkClient.create(PATH + "/node1", "zk-node1".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        zkClient.create(PATH + "/node2", "zk-node2".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }

    /**
     * 获取PATH下的子znode列表
     * @throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void testGetChildren() throws KeeperException, InterruptedException {
        List<String> children = zkClient.getChildren(PATH, true);
        for(String child : children) {
            System.out.println(child);
        }
    }

    /**
     * 获取PATH的znode的数据data
     * @throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void testGetData() throws KeeperException, InterruptedException {
        byte[] data = zkClient.getData(PATH, true, null);
        System.out.println(new String(data));
    }

    /**
     * 判断节点路径是否存在
     * @throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void testExist() throws KeeperException, InterruptedException {
        // 存在则返回Stat 元数据对象, 不存在返回null
        Stat exists = zkClient.exists(PATH, false);
        System.out.println(exists);
        System.out.println(exists == null ? "not exist" : "exist");
    }

    /**
     * 删除叶子节点, 若路径参数不为叶子节点,删除会报错.
     * Zookeeper对象 不支持删除非叶子节点,只能删除完子节点,才能删除父节点
     * @throws InterruptedException
     * @throws KeeperException
     */
    @Test
    public void testDelete() throws InterruptedException, KeeperException {
        // 参数1: 删除的节点路径  参数2: 指定删除的版本, -1表示删除所有版本
        zkClient.delete(PATH+"/node1", -1);
    }


    /**
     * 修改路径节点数据
     * @throws Exception
     * @throws InterruptedException
     */
    @Test
    public void testSetZnode() throws Exception, InterruptedException {
        zkClient.setData(PATH, "modify".getBytes(), -1);

        byte[] data = zkClient.getData(PATH, false, null);
        System.out.println(new String(data));
    }
}

4.2.2 模拟系统服务器上下线动态感知

原理:
服务器端:服务器上线就在zookeeper的/server路径下创建一个EPHEMERAL_SEQUENTIAL类型的znode,znode的data值设为服务器名字。由于znode为短暂类型,当服务器下线,则对应的znode会被自动删除。
客户端: 获取与zookeeper的连接,获取zookeeper的/server路径下的znode,这些znode就为在线的服务器,并对/server路径设置监听,当/server路径下的节点发生变化,则重新获取/server下的节点列表,更新在线服务器列表。

客户端: DistributeClient
服务端 : DistributedServer

4.2.3 模拟实现分布式锁

原理:每个服务器上线在zookeeper的/server路径下生成一个带序号的自动递增短暂节点,客户端使用时取序号最小的服务器,使用完毕后删除该序号最小服务器节点,然后重新生成该服务器节点,下次使用继续取服务器序号最小节点,效果类似轮询。
DistributeClientLock

阅读更多

没有更多推荐了,返回首页