[大数据]Zookeeper

1 Zookeeper

1.1 概述

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

Zookeeper工作机制:
在这里插入图片描述

1.2 特点

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

1.3 数据结构

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

1.4 Zookeeper应用场景

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

1)统一命名服务:
在这里插入图片描述
2)统一配置管理:
在这里插入图片描述
3)统一集群管理
在这里插入图片描述
4)服务器动态上下线
在这里插入图片描述
5)软负载均衡
在这里插入图片描述

2 Zookeeper安装

1)将zookeeper安装包拷贝到 /opt/software
2)解压压缩文件

tar zxf apache-zookeeper-3.5.9-bin.tar.gz -C /opt/module/

3)配置环境变量

sudo vim /etc/profile.d/my_env.sh

添加:

#ZOOKEEPER_HOME
export ZOOKEEPER_HOME=/opt/module/zookeeper
export PATH=$PATH:$ZOOKEEPER_HOME/bin

同步环境变量到集群

sudo xsync.sh /etc/profile.d

4)配置服务器编号

#在/opt/module/zookeeper下创建zkData文件夹
mkdir -p zkData
#在/opt/module/zookeeper/zkData下创建myid文件
touch myid
#编辑myid文件,填写对应server的编号
2
#分发集群上,同时修改对应的myid文件
xsync myid

5)修改配置文件

cd /opt/module/zookeeper/conf
mv zoo_sample.cfg zoo.cfg
vim zoo.cfg

dataDir=/opt/module/zookeeper/zkData #修改数据存储路径配置

#增加配置
server.2=hadoop102:2888:3888
server.3=hadoop103:2888:3888
server.4=hadoop104:2888:3888

同步配置文件

sudo xsync.sh zoo.cfg

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

A是一个数字,表示这个是第几号服务器;
集群模式下配置一个文件myid,这个文件在dataDir目录下,这个文件里面有一个数据就是A的值,Zookeeper启动时读取此文件,拿到里面的数据与zoo.cfg里面的配置信息比较从而判断到底是哪个server。
B是这个服务器的地址;
C是这个服务器Follower与集群中的Leader服务器交换信息的端口;
D是万一集群中的Leader服务器挂了,需要一个端口来重新进行选举,选出一个新的Leader,而这个端口就是用来执行选举时服务器相互通信的端口。

6)启动zookeeper

bin/zkServer.sh start #启动
bin/zkServer.sh status #查看状态

102:(follower)

在这里插入图片描述
103:(leader)
在这里插入图片描述
104:(follower)
在这里插入图片描述

3.Zookeeper操作

3.1 命令行操作

zkCli.sh #进入zookeeper命令行
命令基本语法功能描述
help显示所有操作命令
ls path使用 ls 命令来查看当前znode的子节点
-w监听子节点变化
-s附加次级信息
create普通创建
-s含有序列
-e临时(重启或者超时消失)
get path获得节点的值
-w监听节点内容变化
-s附加次级信息
set设置节点的具体值
stat查看节点状态
delete删除节点
deleteall递归删除节点

3.2 Zookeeper API

3.2.1 环境搭建

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.5.9</version>
		</dependency>
</dependencies>

3)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  

3.2.2 实际操作(增删改查)

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

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

public class ZkClient {
    private ZooKeeper zooKeeper;

    /**
     * 创建zookeeper对象,建立连接
     *
     * @throws IOException
     */
    @Before
    public void before() throws IOException {
        String connectString = "hadoop102:2181,hadoop103:2181,hadoop104:2181";//zookeeper连接地址
        int sessionTimeout = 2000;//会话超时时间
        //1.创建对象
        zooKeeper = new ZooKeeper(
                connectString, //Zookeeeper地址
                sessionTimeout,//超时时间
                new Watcher() { //监听的回调函数 异步通信 返回的通过回调函数通知
                    @Override
                    public void process(WatchedEvent watchedEvent) {
                    }
                });
    }

    /**
     * 创建节点
     *
     * @throws IOException
     * @throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void create() throws IOException, KeeperException, InterruptedException {
        //2.操作集群
        //创建节点
        zooKeeper.create(
                "/testAPI", //节点路径
                "123".getBytes(),//节点值
                ZooDefs.Ids.OPEN_ACL_UNSAFE, //访问控制列表
                CreateMode.PERSISTENT // 节点类型 (四种)
        );
    }

    /**
     * ls查看子节点
     *
     * @throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void ls() throws KeeperException, InterruptedException {
        List<String> children = zooKeeper.getChildren(
                "/",//查询子节点的路径(根目录)
                new Watcher() {//监听,如果根目录子节点有变化,则输出回调函数中的内容
                    @Override
                    public void process(WatchedEvent watchedEvent) {
                        System.out.println("自定义回调函数");
                    }
                }
        );
        for (String child : children) {
            System.out.println(child);
        }
        Thread.sleep(Long.MAX_VALUE);//阻塞主线程,让子线程能监听到请求
    }

    /**
     * get 查询节点的值
     *
     * @throws KeeperException
     * @throws InterruptedException
     * @throws IOException
     */
    @Test
    public void get() throws KeeperException, InterruptedException, IOException {
        Stat stat = new Stat();//节点状态 stat结构体
        byte[] data = zooKeeper.getData("/testAPI", false, stat);
        System.out.println(stat.getDataLength());
        System.out.write(data);
        System.out.println();
    }

    /**
     * 查询节点状态
     *
     * @throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void stat() throws KeeperException, InterruptedException {
        Stat stat = zooKeeper.exists("/testAPI", false);
        if (stat == null) {
            System.out.println("节点不存在");
        } else {
            System.out.println(stat);
        }
    }

    /**
     * 修改节点
     *
     * @throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void set() throws KeeperException, InterruptedException {
        String node = "/testAPI";
        Stat stat = zooKeeper.exists(node, false);
        if (stat == null) {
            System.out.println("节点不存在");
        } else {
            zooKeeper.setData(
                    "/testAPI",
                    "abcd".getBytes(),
                    stat.getVersion()//修改次数 乐观锁 保证要修改的与实际修改的是同一个东西
            );
        }
    }

    /**
     * 删除节点
     *
     * @throws KeeperException
     * @throws InterruptedException
     */
    @Test
    public void delete() throws KeeperException, InterruptedException {
        zooKeeper.delete(
                "/testAPI",
                1
        );
    }

    /**
     * 关闭资源
     * @throws InterruptedException
     */
    @After
    public void after() throws InterruptedException {

        zooKeeper.close();
    }
}

4 Zookeeper内部原理

4.1 节点类型

在这里插入图片描述

4.2 Stat结构体

(1)czxid-创建节点的事务zxid
每次修改ZooKeeper状态都会收到一个zxid形式的时间戳,也就是ZooKeeper事务ID。
事务ID是ZooKeeper中所有修改总的次序。每个修改都有唯一的zxid,如果zxid1小于zxid2,那么zxid1在zxid2之前发生。
(2)ctime - znode被创建的毫秒数(从1970年开始)
(3)mzxid - znode最后更新的事务zxid
(4)mtime - znode最后修改的毫秒数(从1970年开始)
(5)pZxid-znode最后更新的子节点zxid
(6)cversion - znode子节点变化号,znode子节点修改次数
(7)dataversion - znode数据变化号
(8)aclVersion - znode访问控制列表的变化号
(9)ephemeralOwner- 如果是临时节点,这个是znode拥有者的session id。如果不是临时节点则是0。
(10)dataLength- znode的数据长度
(11)numChildren - znode子节点数量

4.3 监听器原理

在这里插入图片描述

4.4 选举机制

(1)半数机制:集群中半数以上机器存活,集群可用。所以Zookeeper适合安装奇数台服务器。
(2)Zookeeper虽然在配置文件中并没有指定Master和Slave。但是,Zookeeper工作时,是有一个节点为Leader,其他则为Follower,Leader是通过内部的选举机制临时产生的。
(3)以一个简单的例子来说明整个选举的过程。
假设有五台服务器组成的Zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的。假设这些服务器依序启动,来看看会发生什么。
在这里插入图片描述
(1)服务器1启动,发起一次选举。服务器1投自己一票。此时服务器1票数一票,不够半数以上(3票),选举无法完成,服务器1状态保持为LOOKING;
(2)服务器2启动,再发起一次选举。服务器1和2分别投自己一票并交换选票信息:此时服务器1发现服务器2的ID比自己目前投票推举的(服务器1)大,更改选票为推举服务器2。此时服务器1票数0票,服务器2票数2票,没有半数以上结果,选举无法完成,服务器1,2状态保持LOOKING
(3)服务器3启动,发起一次选举。此时服务器1和2都会更改选票为服务器3。此次投票结果:服务器1为0票,服务器2为0票,服务器3为3票。此时服务器3的票数已经超过半数,服务器3当选Leader。服务器1,2更改状态为FOLLOWING,服务器3更改状态为LEADING;
(4)服务器4启动,发起一次选举。此时服务器1,2,3已经不是LOOKING状态,不会更改选票信息。交换选票信息结果:服务器3为3票,服务器4为1票。此时服务器4服从多数,更改选票信息为服务器3,并更改状态为FOLLOWING;
(5)服务器5启动,同4一样当小弟。

4.5 写数据流程

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值