Zookeeper(一) —— 环境搭建

一、概述

集中式 向 分布式演变,高并发、海量存储

应用场景:

* 数据发布、订阅的两种方式:推模式、拉模式
* 命名服务
* 分布式协调/通知(心跳检测)
* 负载均衡

自增长id和uuid的缺点,前者只能在单表中使用,后者可在分布式环境使用,但不易于理解、寻找规律

二、基本概念

1、集群中的角色:

* Leader
* Follower
* Observer

2、会话

客户端与Zookeeper的连接,其连接是通过TCP长连接,保持会话,客户端会向Zookeeper端上报心跳。会话也被叫做Session

3、版本

版本的作用是进行分布式锁控制,锁分为两种,悲观锁和乐观锁
悲观锁适合并发竞争激烈的场景,能避免数据不一致的情况,上一个事务没完成,下一个事务不能开始。乐观锁的并发控制是,加入版本号,每次读取记录时首先会获得版本号,插入数据时,也会将版本号带到参数中,若更新失败,说明其他事务已经修改过数据,会抛出异常给客户端,让其进行处理(重试)

version 当前数据内容节点版本号
cversion 当前数据子节点版本号
aversion 当前数据节点ACL变更版本号

4、节点

服务器(节点)
数据模型中的节点

5、watcher

客户端可以在zookeeper中注册watcher,当zookpeer上的内容改变时,会通知客户端获取

6、ACL权限控制

CREATE 创建子节点的权限
READ 读取节点数据、子节点列表的权限
WRITE 更新节点数据的权限
DELETE 删除子节点的权限
ADMIN 设置节点ACL权限

三、环境安装

1、创建文件夹
/opt 用来安装自己的应用软件
/var 用来存放日志输出

2、下载zookeeper
wget 下载链接

3、进行配置
(1)修改Zoo.cfg

dataDir 是用来存放数据快照
clientPort 对外提供的端口号,默认2181
server.id=ip:port:port

server.1=ip:port:port
server.2=ip:port:port
server.3=ip:port:port

(2)在/var/zookeeper中创建myid,内容为id编号,如1

4、启动

export ZK_HOME = /../zookeeper
export PATH=\(PATH:\)ZK_HOME/bin

Zookeeper/bin zkServer.sh start
telnet ip port(2181)
输入 stat 查看状态

四、zk命令

1、启动客户端连接到服务器
zkCli.sh -server serverip:2181

help

quit

ls /   //列出节点

create  /path content

get /path   //查看数据

set /path conent //设置数据

delete  /path      //删除一个节点

rmr /a                //递归删除所有节点

五、通过API访问zk

1、获取根下的目录

(1) 导入依赖包


        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.9</version>
        </dependency>

(2)测试代码

fonxian1 对应的是zk服务器的ip地址

        
@org.junit.Test
public void ls() throws Exception{
    ZooKeeper zk = new ZooKeeper("fonxian1:2181",10000,null);
    List<String> list = zk.getChildren("/",false);
    for(String str:list){
     System.out.println(str);
    }

}

2、递归获取根下所有文件名


    @org.junit.Test
    public void lsAll() {
        try {
            ls("/");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public void ls(String path) throws Exception {

        ZooKeeper zk = new ZooKeeper("fonxian1:2181", 10000, null);
        List<String> list = zk.getChildren(path, false);
        if (list == null || list.isEmpty()) {
            return;
        }
        for (String str : list) {
            if ("/".equals(path)) {
                System.out.println(path + str);
                ls(path + str);
            } else {
                System.out.println(path + "/" + str);
                ls(path + "/" + str);
            }

        }

    }


3、添加数据


@org.junit.Test
    public void setData () {

        try{
        ZooKeeper zk = new ZooKeeper("fonxian1:2181", 10000, null);
        zk.setData("/a","fonxian".getBytes(),2);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

出现版本号错误的提示

org.apache.zookeeper.KeeperException$BadVersionException: KeeperErrorCode = BadVersion for /a

	at org.apache.zookeeper.KeeperException.create(KeeperException.java:115)
	at org.apache.zookeeper.KeeperException.create(KeeperException.java:51)
	at org.apache.zookeeper.ZooKeeper.setData(ZooKeeper.java:1327)
	at com.fonxian.ZookeepTest.setData(ZookeepTest.java:47)

原因是Zookeeper服务器中/a的版本号为0,将代码中的版本号设置为0,即可执行成功

[zk: 127.0.0.1(CONNECTED) 0] get /a
tom
cZxid = 0x200000002
ctime = Sun Mar 18 15:49:45 CST 2018
mZxid = 0x200000002
mtime = Sun Mar 18 15:49:45 CST 2018
pZxid = 0x20000000f
cversion = 3
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 3

4、添加临时节点

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

参数s ,表示序列节点,会在父节点下创建一个10个0+父节点名的节点
参数e,表示临时节点,临时节点在会话结束时会被删除,在leader选举中扮演重要作用


@Test
    public void setTempData() {

        try {

            ZooKeeper zk = new ZooKeeper("fonxian1:2181", 10000, null);
            zk.create("/a/t","fonxian".getBytes(), ZooDefs.Ids.READ_ACL_UNSAFE, CreateMode.EPHEMERAL);
            System.out.println("hello");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

5、使用观察者

观察者的作用在于,当数据发生修改,服务器会通知客户端数据修改,每次注册,只会通知一次。


@Test
    public void testWatch(){

        try {

            final ZooKeeper zk = new ZooKeeper("fonxian1:2181", 50000, null);

            Watcher w = new Watcher() {

                public void process(WatchedEvent watchedEvent) {
                    try{
                        System.out.println("data change");
                        byte[] newData = zk.getData("/a",this,null);
                        System.out.println("new data = "+new String(newData));
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            } ;

            byte[] data = zk.getData("/a",w,null);
            System.out.println(new String(data));

            while(true){

            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

posted @ 2016-08-18 00:37  清泉白石  阅读(219)  评论(0编辑  收藏  举报