Zookeeper集群搭建+客户端命令行操作+内部原理ZAB协议+API

  • 协调大数据之间的框架合作

  • 入门

    • Zookeeper为分布式应用提供协调服务的Apache项目  观察者模式

    • 工作机制

      • 存数据,通知注册过的观察者   ----协调

      • Zookeeper 特点 :

      • 主从(leader-follower)

          • 6)实时性,在一定时间范围内,Client能读到最新数据

      • 数据结构

        • 和unix不同,每个节点是ZNode 可以存数据也可以有子节点 ,可以是文件也可是文件夹

      • 应用场景:HA,Kafka,HBase(只需要把zookeeper打开就可以了)

      • 下载地址:zookeeper.apache.org     雅虎开发的zookeeper 

  • 安装

    • 搭建Zookeeper

      • cd /opt/software/

      • 传入zookeeper的包

      • tar -zxf zookeeper-3.4.10.tar.gz -C /opt/module/

      • cp  zoo_sample.cfg zoo.cfg

      • bin/zkServer.sh start    完成单节点启动

    • 配置zookeeper集群

      • bin/zkServer.sh stop

      • cd conf

      • vim zoo.cfg

      • dataDir=/opt/module/zookeeper-3.4.10/zkData

    • 集群配置

      • 加上这三行    server.2(id)=hadoop102(ip):2888(客户端连接端口):3888(选举端口号)

                        server.2=hadoop102:2888:3888

                        server.3=hadoop103:2888:3888

                        server.4=hadoop104:2888:3888

      • 改完后cd ..

      • mkdir zkData

      • cd zkData/

      • touch myid

      • vim myid    写个2

    • cd ..

    • cd bin

    • vim zkEnv.sh

      • ZOO_LOG_DIR="/opt/module/zookeeper-3.4.10/logs"

      • 配置java_Home

      • 在开头写 export JAVA_HOME=/opt/module/jdk1.8.0_144

    • 总结:

      • 在zoo.cfg配置了zkData存储文件位置和集群信息

      • 在conf中配置zkEnv 的日志和javahome

      • 在zkData中新建myid文件

        • xsync zookeeper

        • 分发完后修改myid 为对应id

    • 启动

      • bin/zkServer.sh start

      • bin/zkServer.sh status   显示ERROR是因为zookeeper需要半数以上结点存活才可正常服务

  • 实战(*!)

    • zookeeper命令行操作

    • 连接zookeeper   bin/zkCli.sh  不加端口号 默认连接本机的服务器

      • $ bin/zkCli.sh -server 127.0.0.1:2181

      •  客户端命令行操作

命令基本语法

功能描述

help

显示所有操作命令

ls path [watch]

使用 ls 命令来查看当前znode中所包含的内容

ls2 path [watch]

查看当前节点数据并能看到更新次数等数据

create

普通创建

-s  含有序列

-e  临时(重启或者超时消失)

get path [watch]

获得节点的值

set

设置节点的具体值

stat

查看节点状态

delete

删除节点

rmr

递归删除节点

    • ls /zookeeper

    • 注册

      • ls / watch   

      • 注册之后如果 /目录发生变化,zookeeper会通知 所有的观察者

    • 创建结点

      •  create /tt1234 abcdef

        • /tt1234 是结点名称, abcdef是结点之后存储的数据

      • 参数 -s

        • 创建一个带序号的结点   全局递增   文件名拼接序号

      • 参数 -e 

        • 创建一个临时结点,在(会话结束)quit后临时结点会消失

        • 如果是有序的临时结点

          • 退出后,再创建有序结点,序号会自增 跳过临时序号

          • 临时结点无法建立子节点

    • 结点类型共四种

    • 获取结点数据 get 

      • get /ttt [watch]   

        • 在set后会出现监听事件(注册列表只会监听一次)

    • 设置结点数据 set

      • set /ttt 2345

    • 查看结点状态 stat /ttt

      • Stat结构体

        •  

        • 1)czxid-创建节点的事务zxid

          •    前4字节表示第几次启动,后8字节表示 第几次操作

          • 每次修改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子节点数量

    • 删除结点

      • delete 只能删除空结点(无子节点)

      • rmr  /ttt    递归删除结点

  • 内部原理

    • 监听器原理

      • new Zookeeper时新建两个子线程(异步)

    • ZAB协议 zookeeper atomic broadcast  

      • 保证了数据顺序一致性

      • 简单说就是两件事

        • 没有leader选leader (术语:崩溃恢复)

        • 有leader了就干活(术语:正常读写)

      • Paxos算法(扩展)

        • zookeeper借鉴了Paxos算法

    • 选举机制

      • 半数机制:集群中半数以上机器存活,集群可用。所以Zookeeper适合安装奇数台服务器。

      • Zookeeper虽然在配置文件中并没有指定Master和Slave。但是,Zookeeper工作时,是有一个节点为Leader,其他则为Follower,Leader是通过内部的选举机制临时产生的。

      • 选举案例

        •  上来先投自己

        • (1)服务器1启动,此时只有它一台服务器启动了,它发出去的报文没有任何响应,所以它的选举状态一直是LOOKING状态。

        • (2)服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出,但是由于没有达到超过半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1、2还是继续保持LOOKING状态。

        • (3)服务器3启动,根据前面的理论分析,服务器3成为服务器1、2、3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的Leader。

        • (4)服务器4启动,根据前面的分析,理论上服务器4应该是服务器1、2、3、4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能接收当小弟的命了。

        • (5)服务器5启动,同4一样当小弟。

    • 写数据流程【一致性,顺序性】

      • 超过半数不同意则返回客户端不同意   ,同意的数据回滚

      • 多数同意少数不同意,则不同意的server 重启 之后向leader或成功同步数据 

        • 这种情况的发生是因为网络原因,延迟收到待写队列中的数据,其他服务器已经将数据落实。

      • 待写队列是按照操作编号顺序落实的,就算延迟收到,也不会乱序。

    • Observer (代表集群规模很大 / 集群跨数据中心)

      • 比如有30000台服务器的集群

        • 三台leader ,其余29997台Observer

          • 正常运行的条件:是leader 存活半数以上

  • API

    • 建立Maven 项目

    •   加入log4j 和依赖 pom.xml

<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.4.10</version>

</dependency>

</dependencies>

    • ZkClient.java

    • Watcher 是一个接口,匿名内部类中实现的方法是回调方法

      • ls    ----》getChildren

        •  卡住等待监听事件

          • 可以在方法中自定义回调函数

      • create----》 create

        • ACL 权限控制  开放 ZooDefs.Ids.OPEN_ACL_UNSAFE

        • 四种文件模式, 临时-e,持久,临时+顺序-e -s,持久+顺序 -s

      • get  ---》getData

      • set  --->setData

        • 最好通过exists 的stat.getVersion

      • stat ---》exists 如果结点存在返回stat

      • delete 

    • Zookeeper API实现 循环注册监听

    API测试代码

import java.lang.String;
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;

public class ZookeeperTest {
    private ZooKeeper zooKeeper;
    private static final String SERVER="hadoop1002:2181,hadoop1003:2181,hadoop1004:2181";
    private static final int SS_TIMEOUT=2000;
    @Before
    public void before() throws IOException {
        zooKeeper=new ZooKeeper(SERVER, SS_TIMEOUT, new Watcher() {
            //这是一个回调方法! 可以自定义
            public void process(WatchedEvent watchedEvent) {
                System.out.println("默认监听器");
            }
        });
    }

    @Test
    public void ls () throws KeeperException, InterruptedException {
        List<String> children = zooKeeper.getChildren("/", true);
        System.out.println("=========================");
        for(String s:children)
        {
            System.out.println(s);
        }
        System.out.println("=========================");
    }

    @Test
    public void create() throws KeeperException, InterruptedException {
        String s = zooKeeper.create("/IDEA", "stw".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        System.out.println(s);
        Thread.sleep(Long.MAX_VALUE);//因为创建的是临时结点,如果直接跳出结点会消失
    }
    @Test
    public void get() throws KeeperException, InterruptedException {
        Stat exists = zooKeeper.exists("/aaa", false);
        if (exists != null) {
            byte[] data = zooKeeper.getData("/aaa", false, exists);
            System.out.println(new String(data));
        }
        else
            System.out.println("文件不存在");
    }

    @Test
    public  void set() throws KeeperException, InterruptedException {
        Stat exists = zooKeeper.exists("/aaa", false);
        if (exists != null) {
            zooKeeper.setData("/aaa", "stw.dadasdasd".getBytes(),exists.getVersion());
            System.out.println(exists.getDataLength());
        }
    }
    public void delete() throws KeeperException, InterruptedException {
        Stat exists = zooKeeper.exists("/aaa", false);
        if(exists!=null) {
            zooKeeper.delete("/aaa", exists.getVersion());
            System.out.println("delete completed");
        }

        else
            System.out.println("要删除的结点不存在");
    }
    @Test
    public void rmr() throws KeeperException, InterruptedException {
        //rmr
        ZKUtil.deleteRecursive(zooKeeper,"/aaa");
    }



    public void register() throws KeeperException, InterruptedException {
        byte[] data = zooKeeper.getData("/aaa", new Watcher() {
            public void process(WatchedEvent watchedEvent) {
                try {
                    register();
                } catch (KeeperException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, null);
        System.out.println(new String(data));
    }
    @Test
    public void testReg()  {
        try {
            register();
            Thread.sleep(Long.MAX_VALUE);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值