大数据之Zookeeper

1 Zookeeper简介

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

1.1 Zookeeper工作机制

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

1.2 Zookeeper特点

在这里插入图片描述

  1. Zookeeper集群由一个Leader和多个Fllower组成。
  2. Zookeeper集群中只要有半数以上节点存活,Zookeeper集群就能正常服务。
  3. 全局数据一致:客户端与单个Zookeeper服务器间维护着一个TCP连接,通过它发送请求,获取响应,获取监视事件并发送心跳,如果与服务器的TCP连接断开,则客户端将连接到其他的服务器,获取的数据是一致的。
  4. 更新请求顺序执行,来自同一Client的更新请求按其发送顺序依次执行。
  5. 数据更新原子性,一次数据更新要么成功,要么失败。
  6. 实时性,在一定时间范围内,Client能读到最新数据。

1.3 数据结构

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

1.4 应用场景

Zookeeper提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2 Zookeeper安装

2.1 本地模式安装部署

  1. 安装JDK
  2. copy Zookeeper安装包到linux系统下
  3. 解压到指定目录
    #解压zookeeper-3.4.13.tar.gz
    [root@bme244 software]# tar -zxvf zookeeper-3.4.13.tar.gz -C /opt/module/
    
  4. 配置修改
    #配置文件
    [root@bme244  zookeeper-3.4.13]# mv conf/zoo_sample.cfg conf/zoo.cfg
    #修改数据存放目录
    [root@bme244  zookeeper-3.4.13]# vim conf/zoo.cfg
    dataDir=../data
    #创建目录
    [root@bme244  zookeeper-3.4.13]# mkdir data
    
  5. 操作Zookeeper
    #{start|start-foreground|stop|restart|status|print-cmd}
    #Zookeeper启动
    [root@bme244  zookeeper-3.4.13]# bin/zkServer.sh start
    
    #客户端连接
    [root@bme244  zookeeper-3.4.13]# bin/zkCli.sh
    

2.2 配置参数

# 通信心跳数,Zookeeper服务器与客户端心跳间隔(ms),最小的session超时时间为2*tickTime。
tickTime=2000
# 初始通信时限,集群中Follower与Leader之间初始连接时能容忍的最多tickTime数,用它来限定集群中的Zookeeper服务器连接到Leader的时限。
initLimit=10
# 同步通信时限,集群中Leader与Follower之间的最大响应时间,假如响应超过syncLimit * tickTime,Leader认为Follwer死掉,从服务器列表中删除Follwer。
syncLimit=5
# 数据文件目录+数据持久化路径
dataDir=../data
# 客户端连接端口
clientPort=2181
# 客户端最大连接数
#maxClientCnxns=60

# 保留到dataDir中的快照数
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1

2.3 分布式安装部署

  1. 集群规划
    在hadoop102、hadoop103和hadoop104三个节点上部署Zookeeper。
  2. 三个节点上分别解压安装
    [yut@hadoop101 module]$ tar -zxvf ../software/zookeeper-3.5.4-beta.tar.gz -C ./
    
  3. 配置服务器编号
    #创建dataDir目录
    [yut@hadoop101 zookeeper-3.5.4-beta]$ mkdir data
    #创建myid文件,并填写编号
    [yut@hadoop101 zookeeper-3.5.4-beta]$ vim data/myid
    1
    
    三个节点下相同操作,注意填写的myid不同,此处hadoop101、hadoop102、hadoop103分别是1、2、3
  4. 配置zoo.cfg文件
    #使用绝对路径,经测试集群模式下使用相对路径无法启动
    dataDir=/opt/module/zookeeper-3.5.4-beta/data
    #集群配置,注意防火墙开启相应端口
    server.1=hadoop101:2888:3888
    server.2=hadoop102:2888:3888
    server.3=hadoop103:2888:3888
    

    server.A=B:C:D
    A:myid,zookeeper启动时会读取myid文件并与zoo.cfg中配置信息比较确定server
    B:服务器id地址
    C:集群中Leader与Follower交换信息的端口
    D:Leader服务器挂掉后,用于选举相互通信的端口

  5. 启动集群
    [yut@hadoop101 zookeeper-3.5.4-beta]$ bin/zkServer.sh start
    [yut@hadoop102 zookeeper-3.5.4-beta]$ bin/zkServer.sh start
    [yut@hadoop103 zookeeper-3.5.4-beta]$ bin/zkServer.sh start
    

2.4 客户端操作

2.4.1 shell操作

主要命令:

命令基本语法功能描述
help显示所有操作命令
ls path [watch]使用 ls 命令来查看当前znode中所包含的内容
ls2 path [watch]查看当前节点数据并能看到更新次数等数据
create普通创建,-s 含有序列,-e 临时(重启或者超时消失)
get path [watch]获得节点的值
set设置节点的具体值
stat查看节点状态
delete删除节点
rmr递归删除节点

2.4.2 Stat结构体

  • cZxid:创建节点的事务zxid,每次修改ZooKeeper状态都会收到一个zxid形式的时间戳,也就是ZooKeeper事务ID。事务ID是ZooKeeper中所有修改总的次序。每个修改都有唯一的zxid,如果zxid1小于zxid2,那么zxid1在zxid2之前发生。在 ZAB ( ZooKeeper Atomic Broadcast , ZooKeeper 原子消息广播协议) 协议的事务编号 Zxid设计中,Zxid 是一个 64 位的数字,其中低 32 位是一个简单的单调递增的计数器,针对客户端每一个事务请求,计数器加 1;而高 32 位则代表 Leader 周期 epoch 的编号,每个当选产生一个新的 Leader 服务器,就会从这个 Leader 服务器上取出其本地日志中最大事务的 ZXID,并从中读取epoch 值,然后加 1,以此作为新的 epoch,并将低 32 位从 0 开始计数。Zxid(Transaction id)类似于 RDBMS 中的事务 ID,用于标识一次更新操作的 Proposal(提议)ID。为了保证顺序性,该 zkid 必须单调递增。
  • ctime:znode被创建的毫秒数(从1970年开始)
  • mZxid:znode最后更新的事务zxid
  • mtime:znode最后修改的毫秒数(从1970年开始)
  • pZxid:znode最后更新的子节点zxid
  • cversion:znode子节点变化号,znode子节点修改次数
  • dataversion:znode数据变化号
  • aclVersion:znode访问控制列表的变化号
  • ephemeralOwner:如果是临时节点,这个是znode拥有者的session id。如果不是临时节点则是0。
  • dataLength:znode的数据长度
  • numChildren:znode子节点数量

3 Zookeeper内部原理

3.1 选举机制

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

zookeeper提供了三种方式:

  • LeaderElection
  • AuthFastLeaderElection
  • FastLeaderElection (最新默认)

以下是默认的算法FastLeaderElection选举流程简述:

目前有5台服务器,每台服务器均没有数据,它们的编号分别是1,2,3,4,5,按编号依次启动,它们的选择举过程如下:

  • 服务器1启动,给自己投票,然后发投票信息,由于其它机器还没有启动所以它收不到反馈信息,服务器1的状态一直属于Looking(选举状态)。
  • 服务器2启动,给自己投票,同时与之前启动的服务器1交换结果,由于服务器2的编号大所以服务器2胜出,但此时投票数没有大于半数,所以两个服务器的状态依然是LOOKING。
  • 服务器3启动,给自己投票,同时与之前启动的服务器1,2交换信息,由于服务器3的编号最大所以服务器3胜出,此时投票数正好大于半数,所以服务器3成为领导者,服务器1,2成为小弟。
  • 服务器4启动,给自己投票,同时与之前启动的服务器1,2,3交换信息,尽管服务器4的编号大,但之前服务器3已经胜出,所以服务器4只能成为小弟。
  • 服务器5启动,后面的逻辑同服务器4成为小弟。

https://www.cnblogs.com/shuaiandjun/p/9383655.html

3.2 节点类型

在这里插入图片描述
Zookeeper的节点根据生命周期可以分为二种类型:

  • 持久(Persistent):客户端和服务端断开连接后,创建的节点不删除
  • 短暂(Ephemeral):客户端和服务端断开连接后,创建的节点自己删除

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

3.3 监听器

3.3.1 监听器原理

在这里插入图片描述

3.3.2 监听服务器节点上下线案例

  1. 创建maven工程,引入以下依赖
<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>
  1. 配置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  
  1. 编写服务端
public class DistributeServer {

    public static void main(String[] args) throws Exception {
        DistributeServer server = new DistributeServer();
        //连接Zookeeper集群
        server.getConnect();

        //注册节点
        server.register(args[0]);

        //业务逻辑处理
        server.business();
    }

    private void business() throws InterruptedException {
        Thread.sleep(Long.MAX_VALUE);
    }

    private void register(String hostname) throws KeeperException, InterruptedException {
        String path = zkClient.create("/servers/server", hostname.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        System.out.println(hostname + " is online");
    }

    private String connectString="hadoop101:2181,hadoop102:2181,hadoop103:2181";
    private int sessionTimeout = 2000;
    private ZooKeeper zkClient;
    private void getConnect() throws IOException {
        zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {

            @Override
            public void process(WatchedEvent event) {

            }
        });
    }
}

  1. 编写客户端
public class DistributeClient {

    public static void main(String[] args) throws Exception {
        DistributeClient client = new DistributeClient();
        //获取Zookeeper连接
        client.getConnect();

        //注册监听
        client.register();

        //业务逻辑处理
        client.business();
    }

    private void business() throws InterruptedException {
        Thread.sleep(Long.MAX_VALUE);
    }

    private void register() throws KeeperException, InterruptedException {
        List<String> children = zkClient.getChildren("/servers", true);

        //存储服务器节点主机名称集合
        ArrayList<String> hosts = new ArrayList<>();

        for (String child : children) {
            byte[] data = zkClient.getData("/servers/" + child, false, null);
            hosts.add(new String(data));
        }
        //将所有在线主机名称打印到控制台
        System.out.println(hosts);
    }

    private String connectString="hadoop101:2181,hadoop102:2181,hadoop103:2181";
    private int sessionTimeout = 2000;
    private ZooKeeper zkClient;
    private void getConnect() throws IOException {
        zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {

            @Override
            public void process(WatchedEvent event) {
                try {
                    register();
                } catch (KeeperException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

3.4 写数据流程

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值