初遇ZooKeeper

写在前面:

之前学习配置ActiveMQ集群时,用到了ZooKeeper,但对ZK不熟悉,只听说过没接触到过。和它经常一起出现的还有Double,作为分布式框架的一对默契搭档。ZK早晚会接触到,既然现在接触到了那就顺便来学习一下ZooKeeper。老样子,把自己学习到的接触到的不熟悉的统统记录成册。日积月累,形成日后自己的技术栈。

一、入门简介

ZooKeeper=文件系统+通知机制

ZooKeeper:开源的分布式系统框架下的“协调调度通知机制”,以便达到消息一致性原则。

ZK可以用来做集中配置管理,存储在ZK集群中的配置。如果发生变更会主动推送到连接配置中心的应用节点,实现一处更新处处更新的效果。

★ZK提供了一套很好的分布式集群管理的机制。它这种基于层次型的目录树的数据结构。并对树中的节点进行有效管理,从而设计出多种多样的分布式的数据管理模型。作为分布式系统的沟通调度桥梁。

二、 安装配置

1.官网下载 tar –zxvfzookeeper-3.4.14.tar.gz

2.cp –r zookeeper-3.4.14.tar.gz/myzookeeper

3.进入conf文件夹,拷贝zoo_sample.cfg改为zoo.cfg做为备份

4.zoo,cfg解读

tickTime:心跳检测时间(毫秒)≈服务器之间或客户端与服务器之间维持间隔

initLimit初始通讯时间 ≈“电话打通前的等待时间”

syncLimit:同步通信时限≈“电话拨通后的等待时间”

dataDir:数据存放目录

clientPort:默认端口2181

5.常见服务命令 /bin目录下

./zkServer.shstart 启动

./zkServer.shstop 关闭

./zkCli.sh 客户端启动

quit 客户端退出服务端的连接

6.四字命令

支持某些特定的四字命令,大多用来查询ZK的当前状态及相关信息

运行公式:echo 四字命令 | nc 主机ip 2181

例如,测试是否启动了服务。

echo ruok | nc 127.0.0.1 2181 回复imok则表示已经启动。

还有,查看当前运行环境配置信息

echo envi | nc 127.0.0.1 2181

★初次运行 可能会报找不到nc。需要安装一下。

7.永远的helloworld

三、数据模型/znode节点深入

查看+获得zookeeper服务器上的数据存储信息

1.Znode的数据模型:Stat结构体

2.ZooKeeper维护了一个类似文件系统的数据结构。这套存储结构为一个树形结构,其上每一个节点,都称为znode。每一个zonde都默认存储1MB,都有唯一的路径标识

Znode =path + pathValue + Stat

3.Znode中存在的类型--------临时&持久

create [-s] [-e] path data acl

【-s】sequential持久化顺序编号目录节点。由ZK对节点进行顺序编号。

【-e】ephemeral临时节点

【-p】persistent持久化

【-s】【-e】可以同时使用【-p】啥都不写 默认持久

四、基础命令和Java客户端操作

1.zkcl的常用命令操作:和redis的KV键值对类似,只不过key变成了一个路径节点值,v就是data。

help

ls:只露出[zookpper]

ls2:2比l更详细,还露出其结构体

stat查看结构体

delete有且只能删除当前节点且节点下无别的节点

rmr递归删除节点

2.Java客户端操作 pom.xml主要的jar包

<!-- https://mvnrepository.com/artifact/com.101tec/zkclient -->
<dependency>
   <groupId>com.101tec</groupId>
   <artifactId>zkclient</artifactId>
   <version>0.10</version>
</dependency>


<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
   <groupId>org.apache.zookeeper</groupId>
   <artifactId>zookeeper</artifactId>
   <version>3.4.9</version>
   <type>pom</type>
</dependency>

五、通知机制

1.Session:连接

2.Watch:(哨兵)客户端可以在znode节点上设置一个观察如果被观察服务端Znode节点有变更,那么watch所属客户端将接收到一个通知包,被告知节点已经发生变化,把相应的事件通知给设置Watch的Client端。

Zookeeper里的所有读取操作:getData()、getChildren()、exists()都有设置watch的选项。一句话:异步+回调触发机制 

*ZK设计模式理解

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

3.HelloZK

public class HeloZK {


    private static final String CONNECTION_STRING = "192.168.91.130:2181";
    private static final String PATH = "/atguigu";
    private static final int SESSIONT_IMEOUT = 50*1000;


    public ZooKeeper startZK() throws IOException {
        return new ZooKeeper(CONNECTION_STRING, SESSIONT_IMEOUT, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
            }
        });
    }


    public void stopZK(ZooKeeper zk) throws InterruptedException {
        if(null != zk) zk.close();
    }


    public void createZnode(ZooKeeper zk,String nodePath,String nodeValue) throws KeeperException, InterruptedException {
        zk.create(nodePath,nodeValue.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }


    public String getZnode(ZooKeeper zk,String nodePath) throws KeeperException, InterruptedException {
        String result = null;


        byte[] data = zk.getData(nodePath, false, new Stat());


        result = new String(data);
        return result;
    }


    public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
        HeloZK heloZK = new HeloZK();


        ZooKeeper zk = heloZK.startZK();


        if(zk.exists(PATH,false)==null){
            heloZK.createZnode(zk,PATH,"12138");
            String znode = heloZK.getZnode(zk, PATH);
            System.out.println("returnValue" + znode);
        }else {
            System.out.println("该节点已经存在");
        }


        heloZK.stopZK(zk);
    }
}

4.WatchOne

*ZooKeeper自带的Bug,若不传watcher将报空指针异常。

public ZooKeeper startZK() throws IOException {
    return new ZooKeeper(CONNECTION_STRING, SESSIONT_IMEOUT, new Watcher() {
        @Override
        public void process(WatchedEvent watchedEvent) {
        }
    });
}

Zookeeper里的所有读取操作:getData()、getChildren()、exists()都有设置watch的选项。

public String getZnode(String nodePath) throws KeeperException, InterruptedException {
    String result = null;


    byte[] data = zk.getData(nodePath, new Watcher() {
        @Override
        public void process(WatchedEvent watchedEvent) {
            try {
                targetValue(nodePath);
            } catch (KeeperException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }, new Stat());


    result = new String(data);
    return result;
}


public String targetValue(String nodePath) throws KeeperException, InterruptedException {
    String result = null;


    byte[] data = zk.getData(nodePath, false, new Stat());
    result = new String(data);
    System.out.println("*******************节点值被修改为了" + result + "当前仅当记录这一次改变 后面再改变 不记录");
    return result;
}

监控/atguigu节点 获得初次值后设置watch 只要发生新的变化 打印出最新的值 一次性watcher。

5.WatchMore

public String getZnode(String nodePath) throws KeeperException, InterruptedException {
    String result = null;


    byte[] data = zk.getData(nodePath, new Watcher() {
        @Override
        public void process(WatchedEvent watchedEvent) {
            try {
                targetValue(nodePath);
            } catch (KeeperException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }, new Stat());


    result = new String(data);
    oldValue = result;
    return result;
}


public boolean targetValue(String nodePath) throws KeeperException, InterruptedException {
    String result = null;


    byte[] data = zk.getData(nodePath, new Watcher() {
        @Override
        public void process(WatchedEvent watchedEvent) {
            try {
                targetValue(nodePath);
            } catch (KeeperException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }, new Stat());
    result = new String(data);


    String newValue = result;


    if(oldValue.equals(newValue)){
        System.out.println("*******************no changges*******************");
        return false;
    }else{
        System.out.println("oldValue===="+oldValue+"newValue==="+newValue);
        oldValue = newValue;
        return true;
    }
}

6.watchChild

public ZooKeeper startZK() throws IOException {
    return new ZooKeeper(CONNECTION_STRING, SESSIONT_IMEOUT, new Watcher() {
        @Override
        public void process(WatchedEvent watchedEvent) {
            if(watchedEvent.getType() == Event.EventType.NodeChildrenChanged && watchedEvent.getPath().equals(PATH)){
                showChild(PATH);
            }else {
                showChild(PATH);
            }
        }
    });
}


public void showChild(String nodePath){
    List<String> children = null;
    try {
        children = zk.getChildren(nodePath,true);
        System.out.println(children);
    }catch (Exception e){
        e.printStackTrace();
    }
}

六、ZooKeeper集群

server.N (服务器编号)= YYY(服务器IP):A(主master从slave):B(选举端口)

(正式)集群中每个服务器A,B端口都一样 伪集群 IP地址都一样 A和B端口也不一样

步骤

1.复制3个

cp –r zookeeper-3.4.14 /myzookeeper/zk01 ..zk02 ..zk03

2.进入zk01、zk02、zk03各自conf文件夹 新建mydata,mylog

3.分别进入zk01、zk02、zk03各自conf文件夹新建zoo.cfg

4.分别编辑zk01、zk02、zk03的zoo.cfg

#dataDir=/tmp/zookeeper

dataDir=/myzookeeper/zk01/mydata

dataLogDir=/myzookeeper/zk01/mylog

 

server.1=127.0.0.1:2991:3991

server.2=127.0.0.1:2992:3992

server.3=127.0.0.1:2993:3993

5.zk01、zk02、zk03各自mydata文件夹下 创建myid文件里面写server.N的数字

2991:1

2992:2

2993:3

6.分别启动三个服务器

7.zkCli.sh连接server 带参数指定 –server

./zkCli.sh –server 127.0.0.1:2193   ----->zk03

zk03:./zkCli.sh –server 127.0.0.1:2193

          create/atguigu hello

zk01:.get /atguigu

          hello

分享最近路上拍到一张的夕阳晚霞~Good luck

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值