zookeeper

1.zookeeper基本概念

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

  • zk的数据模型:树形结构(linux和hdfs也是树形结构)

  • ZK每个节点znode,有一个唯一的路径标识
    (/home/hadoop/app/ruozedata.txt)

  • znode
    1)临时的 ephemeral 临时znode下面不能有子节点
    普通的
    sequential
    2)永久的 persistent 可以有子节点
    普通的
    sequential 顺序编号目录节点

  • 每个znode节点有各自的版本号
    每个节点数据发生了变化,该节点的版本会加(乐观锁)

  • ZK节点存储的数据量不宜过大,几K

  • znode可以设置访问权限

  • znode可以设置watcher:当节点数据发生变化时,可以通过监视器获取

zk特点

在这里插入图片描述

2.zookeeper配置

修改zoo.cfg的dataDir目录

  • linux tmp目录下的文件30天自动清除,所以要修改
dataDir=/home/hadoop/data/zookeeper

3.zkCli

  • 打开zk客户端前先zkServer.sh start
[hadoop@ruozedata000 zookeeper]$ bin/zkCli.sh 
Connecting to localhost:2181
2019-09-06 19:57:57,050 [myid:] - INFO  [main:Environment@100] - Client environment:zookeeper.version=3.4.6-1569965, built on 02/20/2014 09:09 GMT
2019-09-06 19:57:57,054 [myid:] - INFO  [main:Environment@100] - Client environment:host.name=ruozedata000
2019-09-06 19:57:57,054 [myid:] - INFO  [main:Environment@100] - Client environment:java.version=1.8.0_144
2019-09-06 19:57:57,056 [myid:] - INFO  [main:Environment@100] - Client environment:java.vendor=Oracle Corporation
2019-09-06 19:57:57,191 [myid:] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@852] - Socket connection established to localhost/127.0.0.1:2181, initiating session
[zk: localhost:2181(CONNECTING) 0] 2019-09-06 19:57:57,231 [myid:] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@1235] - Session establishment complete on server localhost/127.0.0.1:2181, sessionid = 0x16d066a4de10000, negotiated timeout = 30000

WATCHER::

WatchedEvent state:SyncConnected type:None path:null

[zk: localhost:2181(CONNECTED) 0] 
[zk: localhost:2181(CONNECTED) 0] ls /
[zookeeper]

ls和ls2

  • ls查看当前目录下的子节点
  • ls2是两个命令的综合 ls+get
  • stat和get一样
[zk: localhost:2181(CONNECTED) 2] ls /zookeeper
[quota]

[zk: localhost:2181(CONNECTED) 3] ls2 /zookeeper
[quota]
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = -1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1

[zk: localhost:2181(CONNECTED) 4] get /zookeeper
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = -1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1

[zk: localhost:2181(CONNECTED) 5] stat /zookeeper
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = -1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1
  • cZxid znode 编号
  • mZxid 修改后的id
  • cversion 子节点版本
  • dataVersion 数据版本
  • ephemeralOwner 是否是临时节点
  • numChildren 孩子数量

创建节点

[zk: localhost:2181(CONNECTED) 6] create /ruoze ruoze-data
Created /ruoze

[zk: localhost:2181(CONNECTED) 8] get /ruoze
ruoze-data
cZxid = 0x2
ctime = Fri Sep 06 20:26:59 CST 2019
mZxid = 0x2
mtime = Fri Sep 06 20:26:59 CST 2019
pZxid = 0x2
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 10
numChildren = 0

创建临时节点

[zk: localhost:2181(CONNECTED) 10] create -e /ruoze/tmp ruoze-data
Created /ruoze/tmp
[zk: localhost:2181(CONNECTED) 11] get /ruoze
ruoze-data
cZxid = 0x2
ctime = Fri Sep 06 20:26:59 CST 2019
mZxid = 0x2
mtime = Fri Sep 06 20:26:59 CST 2019
pZxid = 0x3
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 10
numChildren = 1

[zk: localhost:2181(CONNECTED) 12] get /ruoze/tmp
ruoze-data
cZxid = 0x3
ctime = Fri Sep 06 20:29:06 CST 2019
mZxid = 0x3
mtime = Fri Sep 06 20:29:06 CST 2019
pZxid = 0x3
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x16d066a4de10000
dataLength = 10
numChildren = 0
  • 客户端退出后重新进入,刚刚创建的临时节点没有了

sequential

[zk: localhost:2181(CONNECTED) 1] create -s /ruoze/seq seqdata
Created /ruoze/seq0000000001
[zk: localhost:2181(CONNECTED) 2] ls /ruoze
[seq0000000001]
[zk: localhost:2181(CONNECTED) 3] create -s /ruoze/seq seqdata
Created /ruoze/seq0000000002
[zk: localhost:2181(CONNECTED) 4] ls /ruoze                   
[seq0000000001, seq0000000002]

不可以递归创建目录

[zk: localhost:2181(CONNECTED) 6] create /ruoze/a/b/c abc
Node does not exist: /ruoze/a/b/c

版本号变化

[zk: localhost:2181(CONNECTED) 7] get /ruoze
ruoze-data
cZxid = 0x2
ctime = Fri Sep 06 20:26:59 CST 2019
mZxid = 0x2
mtime = Fri Sep 06 20:26:59 CST 2019
pZxid = 0x7
cversion = 4
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 10
numChildren = 2

[zk: localhost:2181(CONNECTED) 8] set /ruoze new-ruozedata
cZxid = 0x2
ctime = Fri Sep 06 20:26:59 CST 2019
mZxid = 0x9
mtime = Fri Sep 06 20:40:51 CST 2019
pZxid = 0x7
cversion = 4
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 13
numChildren = 2

watch

  • zk中的watcher是一次性的
  • NodeCreated
    NodeDataChanged
    NodeDeleted
    NodeChildrenChanged
[zk: localhost:2181(CONNECTED) 2] ls /
[zookeeper]
[zk: localhost:2181(CONNECTED) 3] stat /ruoze watch
Node does not exist: /ruoze
[zk: localhost:2181(CONNECTED) 4] create /ruoze 123

WATCHER::

WatchedEvent state:SyncConnected type:NodeCreated path:/ruoze
Created /ruoze

四字命令

在这里插入图片描述

  • eg
[hadoop@ruozedata000 ~]$ echo conf|nc localhost 2181
clientPort=2181
dataDir=/home/hadoop/data/zookeeper/version-2
dataLogDir=/home/hadoop/data/zookeeper/version-2
tickTime=2000
maxClientCnxns=60
minSessionTimeout=4000
maxSessionTimeout=40000
serverId=0
[hadoop@ruozedata000 ~]$ 

4.API

  • zookeeper
package com.ruozedata.bigdata.zookeeper;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

public class ZookeeperApp implements Watcher {

    private static Logger logger = LoggerFactory.getLogger(ZookeeperApp.class);

    private static CountDownLatch connected = new CountDownLatch(1);

    public static void main(String[] args) throws Exception {

        ZooKeeper zk = new ZooKeeper("ruozedata000:2181", 5000, new ZookeeperApp());

        logger.warn("客户端开始连接zk服务器....");

        logger.warn("连接状态:{}", zk.getState());

        connected.await();
        // Thread.sleep(2000);

        logger.warn("连接状态:{}", zk.getState());

        //同步创建临时节点
//        String path1 = zk.create("/zk-test-eph", "1".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
//
//
//        logger.warn("创建节点成功:{}", path1);
//
//        Thread.sleep(10000);


        //异步创建临时节点

//        String ctx = "{'create','success'}";
//
//        zk.create("/zk-test-eph", "1".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL, new AsyncCallback.StringCallback() {
//            @Override
//            public void processResult(int i, String path, Object ctx, String name) {
//                logger.warn("创建节点成功:{}", name);
//            }
//        },ctx);
//
//        Thread.sleep(10000);

        //不知道当前版本号,可以设置为-1
//        Stat stat = zk.setData("/ruoze", "ruozedata".getBytes(), -1);
//        logger.warn("版本号:{}", stat.getVersion());

//        zk.delete("/ruoze/123",-1);


        //获取节点数据
//        Stat stat = new Stat();
//        byte[] data = zk.getData("/ruoze", true, stat);
//
//        logger.warn("获取节点数据:{}", new String(data));
//        logger.warn("版本号:{}", stat.getVersion());

        //节点是否存在
//        Stat stat = zk.exists("/ruoze", true);
//        if(stat!=null){
//            logger.warn("节点存在");
//        }else {
//            logger.warn("节点不存在");
//        }

        //获取节点列表
        List<String> children = zk.getChildren("/ruoze", true);
        for(String child:children){
            logger.warn(child);
        }
    }

    @Override
    public void process(WatchedEvent watchedEvent) {
        if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
            logger.warn("接收到通知:{}", watchedEvent);
            connected.countDown();
        }
    }
}

5.面试重点

1.选举机制

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

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

  3. 以一个简单的例子来说明整个选举的过程。
    假设有五台服务器组成的 Zookeeper 集群,它们的 id 从 1-5,同时它们都是最新启动的, 也就是没有历史数据,在存放数据量这一点上,都是一样的。假设这些服务器依序启动,来 看看会发生什么,如图
    在这里插入图片描述

(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 一样当小弟。

2.监听器原理

1、监听原理详解:
1)首先要有一个main()线程
2)在main线程中创建Zookeeper客户端,这时就会创建两个线 程,一个负责网络连接通信(connet),一个负责监听(listener)。
3)通过connect线程将注册的监听事件发送给Zookeeper。
4)在Zookeeper的注册监听器列表中将注册的监听事件添加到列表中。
5)Zookeeper监听到有数据或路径变化,就会将这个消息发送 给listener线程。 6)listener线程内部调用了process()方法。

2、常见的监听
1)监听节点数据的变化
get path [watch]
2)监听子节点增减的变化
ls path [watch]
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值