zookeeper基础知识-02

目录

一、zookeeper Java API

1、连接zookeeper

2、新增节点

3、更新节点

4、删除节点

5、查看节点

6、查看子节点

7、判断节点是否存在

二、zookeeper的监听机制

1、连接状态捕获

2、exists的监听机制

3、getData、getChildren的监听机制

三、zookeeper作为配置中心案例

四、利用zookeeper生成分布式唯一ID

五、利用zookeeper生成分布式锁

六、zookeeper开源客户端curator

1、常见curator API

2、curator的Watcher API(监听机制)

3、curator的事务

4、curator的分布式锁

七、zookeeper的监控命令详解


本文将是对zookeeper基础知识的补充,其中涉及到了java的相关内容。与利用jdbc连接数据库一样,我们可以使用idea远程连接zookeeper,然后使用java提供的API操作zk的znode。同样连接zookeeper需要依赖。zookeeper的连接依赖在安装包(linux系统下:/export/server/zookeeper/lib/)里就有:

然后下载netty依赖:netty-3.10.5.Final.jar

后续会使用Junit进行单元测试,高阶JDK已经自动集成。此外还需要log4j的配置文件log4j.properties

下载链接:https://pan.baidu.com/s/1Y_watqwNYC_9iH_X2pi6Ig 
提取码:zxyd

然后将上述依赖全部整合到我们的项目中:

一、zookeeper Java API

1、连接zookeeper

ZooKeeper(String connectionString, int sessionTimeout, Watcher watcher):ZooKeeper类的有参构造器

connectionString:是一个字符串,与使用jdbc连接数据库一样,需要指定连接的zookeeper在哪里(ip:客户端端口2181)

sessionTimeout:会话超时(以毫秒为单位),客户端在限定时间内连接zookeeper服务端,如果超时,就会取消当次连接

watcher:一个监视器对象,zookeeper通过监视器对象返回连接状态。Watcher是一个接口,使用匿名内部类创建对象。当客户端与服务器端的连接成功时,服务器端会给客户端发一个消息,该消息会被watcher监视器事件监听到,一旦监听到会自动回调process方法。

注意如果zookeeper是集群环境connectString参数一般需要填写所有zookeeper服务器ip和端口(必须保证超过半数以上zk服务器)。这里与直接在linux系统上启动zk的客户端不同。

注意:由于zookeeper对象的创建是异步的(执行到new语句时会自动执行一个线程来创建zookeeper对象),因此可能出现new Zookeeper语句执行完主线程往下执行其他代码的时候,zookeeper对象还没创建出来呢!此时需要让主线程等待zookeeper对象创建成功后再向下执行。需要用到计数器对象CountDownLatch(int n)(它是一种同步辅助工具,允许一个或多个线程等待,直到其他n个线程执行的任务完成)。利用watcher监听器通知CountDownLatch什么时候对象创建成功,继续执行。

集群环境下出现以下报错是因为开启的zk服务器没有超过半数以上。

开启的zk服务器超过半数以上了,但每次都是先建立连接成功后又报错,这是正常现象,因为当执行zookeeper.close()释放zookeeper资源时是一个一个释放,释放连接的瞬间一定会产生zk服务器小于半数以上的情况。

2、新增节点

异步方式需要使用回调接口返回是否创建成功,ctx可以为callBack传入参数。acl:ACL权限控制,系统提供有三种方式:(支持自定义)

        ZooDefs.Ids.OPEN_ACL_UNSAFE:完全开放的API,任何连接的客户端都可以操作该节点等同于:world:anyone:cdrwa

        ZooDefs.Ids.CREATOR_ALL_ACL:只有创建者才有ACL权限,用于auth授权模式

        ZooDefs.Ids.READ_ACL_UNSAFE:只能读取等同于:world:anyone:r

createMode用于设置节点类型是有序还是无序呢?是持久还是临时呢?

        CreateMode.PERSISTENT:持久化节点

        CreateMode.EPHEMERAL:临时节点

        CreateMode.EPHEMERAL_SEQUENTIAL :临时有序节点

        CreateMode.PERSISTENT_SEQUENTIAL:持久有序节点

同步方式:

注意:IP虽然设置的所有zk服务器的ip和端口,但是create4方法在实际执行过程中本质上还是在192.168.11.141的客户端上执行的,因此只有通过192.168.11.143远程连接192.168.11.141客户端才有权访问。

首先添加授权用户才有权访问:

由于执行完成后会话自动关闭,其实创建出的临时节点已经不存在了。

异步方式:

3、更新节点

version填写-1表示不检测数据版本

同理提前写好@After和@Before。先提前创建出/set/node1节点,内容是node1同步方式:

setData有返回值是Stat类型的对象,用于返回该节点修改后的元数据:

异步方式:

4、删除节点

注意:这里的delete方法只能删除没有子节点的节点。非空节点无法删除。原生zookeeper javaAPI无法删除非空节点

5、查看节点

6、查看子节点

7、判断节点是否存在

可以先判断stat是否等于null,等于null节点不存在,如果不等于null,则返回版本号说明节点存在

二、zookeeper的监听机制

zookeeper提供了数据的发布与订阅功能(Watcher接口),多个订阅者(客户端)可同时监听某一特定主题对象(znode节点),当该主题对象的自身状态发生变化时(例如节点内容,节点的子节点发生变化),监听器会实时的监听到,并以异步方式通知所有订阅者。

java实现zk的监听是使用Watcher接口实现的。首先需要在java代码中获得一个实现了Watcher接口的实现类对象(该对象就是监听器),然后将该对象注册到zk的服务器上。一旦服务器上的某个znode节点发生变化时这个监听器就会捕获到这个事件,并自动调用自己的process回调方法通知客户端相关节点发生变化。

zk监听机制的特征:

本质上:客户端创建了监听器对象后会将该对象注册到zk的服务器上,同时会将该对象保存到一个WatchManager容器内,当服务端的某个znode节点发生变化,监听器对象会监听到该事件,然后会将监听到的事件信息提交给WatchManager容器内的监听器对象。客户端想要得到事件信息,必须回调WatchManager容器内监听器对象的process方法。这就是客户端的顺序回调。

Watcher接口:

WatchedEvent就是捕获到的事件对象,其内部保存了所有的事件信息(比如事件类型和连接状态)。事件类型(EventType)和连接状态(KeeperState)都是枚举类用于标记有那些事件类型和连接状态。事件类型有5种分别是:

        None:无

        NodeCreate:Watcher监听的数据节点被创建

        NodeDeleted:Watcher监听的数据节点被删除

        NodeDataChanged:Watcher监听的数据节点内容发生变化

        NodeChildrenChanged:Watcher监听的数据节点的子节点列表发生变化

KeeperStat是客户端与服务端连接状态发生变化时对应的通知类型。有4种:

        SyncConnected:客户端与服务端正常连接

        Disconneted:客户端与服务端异常断开连接

        Expired:会话session失效

        AuthFailed:添加授权用户失败(也称认证失败)在添加授权用户时addauth digest itcast:123456, digest命令输入错误。比如addauth digest1 itcast:123456而导致的添加授权用户失败

注意:只有客户端与服务器端正常连接以后Watcher才可以进行监听服务端znode节点的变化,即当KeeperStat发生变化的时候,EventType永远为None,当EventType发生变化时KeeperStat永远处于SyncConnected成功连接状态。下面是所有可以创建Watcher对象的api(共有两大类)

在与zk服务端连接时可以设置一个Watcher对象,一旦建立连接成功Watcher会监听到服务端发来的成功事件WatchedEvent,并自动回调process方法通知客户端连接创建成功(主要用于监听KeeperStat,EventType=None)。

这些api主要监听数据节点的变化:EventType,KeeperStat=SyncConnected。

1、连接状态捕获

右键运行会直接捕获到连接创建成功,当我们把vmware8网卡关闭时,客户端与服务端的连接会异常断开,Watcher会捕获到断开连接,断开连接后系统会保留zookeeper对象5s(sessionTimeout),当我们在5秒之内打开网卡系统又会自动连接上。但是当断开连接的时间超过5s,zookeeper对象就会被销毁,此时再次打开网卡由于会话超时当前的会话已经不可用了,服务端给客户端发来的会话超时事件被Watcher捕获到。

默认情况下AuthFailed只会被监听器监听到, 不会像异常断开连接、会话超时一样会报异常。想要让其报出异常,需要对某个节点进行操作,这样系统才会识别到AuthFailed异常并报出。

2、exists的监听机制

刚开始path=null,eventType=None

启动以后在另一个客户端创建/watcher1节点,修改数据,删除节点:

同理......。注意Watcher是一次性的,先创建/watcher1,然后不停的对节点进行修改,只能监听到创建/watcher1。如果我就想让Watcher能监听到每次操作,这怎么实现呢?

针对同一个节点,我们可以注册多个监听器对象,一旦该节点发生变化,服务端会以异步方式给所有客户端发消息,所有的监听器都会监听到对应的事件信息,然后回调process方法。

3、getData、getChildren的监听机制

后面同exists一样......。针对getData方法,如果想让Watcher能监听到每次修改,只有是节点内容发生变化时才重新监听,如果节点都删除了就没必要监听了(会报错)。

getChildren与getData一模一样,这里省略。(这里只能监听到子节点列表发生变化,子节点内容的变化监听不到)

三、zookeeper作为配置中心案例

场景:将连接Mysql数据库的ip,端口、用户名和密码存储在配置中心(本质就是将ip、端口、用户名、密码存储在zk的znode节点下),客户端连接zk服务器读取配置信息存入本地变量,并注册Watcher监听器监听配置中心信息的变化。当配置信息发生变化时,通过Watcher监听器的回调process方法捕获数据变化事件,然后客户端重新获取全新的配置信息,并且再次开启监听。

首先初始化配置中心:

package com.itcast.example;

import java.util.concurrent.CountDownLatch;

import com.itcast.watcher.ZKConnectionWatcher;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.ZooKeeper;

public class MyConfigCenter implements Watcher {

    //  zk的连接串
    String IP = "192.168.11.141:2181,192.168.11.142:2181,192.168.11.143:2181";
    //  计数器对象
    CountDownLatch countDownLatch = new CountDownLatch(1);
    // 连接对象
    static ZooKeeper zooKeeper;

    // 用于本地化存储配置信息
    private String url;
    private String username;
    private String password;

    @Override
    public void process(WatchedEvent event) {
        try {
            // 捕获事件状态
            if (event.getType() == Event.EventType.None) {
                if (event.getState() == Event.KeeperState.SyncConnected) {
                    System.out.println("连接成功");
                    countDownLatch.countDown();
                } else if (event.getState() == Event.KeeperState.Disconnected) {
                    System.out.println("连接断开!");
                } else if (event.getState() == Event.KeeperState.Expired) {
                    System.out.println("连接超时!");
                    // 超时后服务器端已经将连接释放,需要重新连接服务器端
                    zooKeeper = new ZooKeeper(IP, 6000,
                            new MyConfigCenter());
                } else if (event.getState() == Event.KeeperState.AuthFailed) {
                    System.out.println("验证失败!");
                }
                // 当配置信息发生变化时
            } else if (event.getType() == Event.EventType.NodeDataChanged) {
                 this.url = new String(zooKeeper.getData("/config/url", true, null));
                 this.username = new String(zooKeeper.getData("/config/username", true, null));
                 this.password = new String(zooKeeper.getData("/config/password", true, null));
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    // 构造方法
    public MyConfigCenter() {
        initValue();
    }

    // 连接zookeeper服务器,读取配置信息
    public void initValue() {
        try {
            // 创建连接对象
            zooKeeper = new ZooKeeper(IP, 5000, this);
            // 阻塞线程,等待连接的创建成功
            countDownLatch.await();
            // 读取配置信息
            this.url = new String(zooKeeper.getData("/config/url", true, null));
            this.username = new String(zooKeeper.getData("/config/username", true, null));
            this.password = new String(zooKeeper.getData("/config/password", true, null));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) {
        try {
            MyConfigCenter myConfigCenter = new MyConfigCenter();
            for (int i = 1; i <= 20; i++) {
                Thread.sleep(5000);
                System.out.println("url:"+myConfigCenter.getUrl());
                System.out.println("username:"+myConfigCenter.getUsername());
                System.out.println("password:"+myConfigCenter.getPassword());
                System.out.println("########################################");
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

我们可以多开实例模拟多个客户端访问配置中心。 一旦配置中心的配置信息发生变化所有的客户端都可以监听到,并可以获取最新的配置信息。

四、利用zookeeper生成分布式唯一ID

场景:在单库单表型系统中,通常可以使用数据库自带的auto_increment关键字来自动为每条记录生成唯一ID。但是分库分表后auto_increment就无法使用了,此时就需要利用zk在分布式环境下生成全局唯一ID。

package com.itcast.example;

import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;

public class GloballyUniqueId implements Watcher {
    //  zk的连接串
    String IP = "192.168.11.141:2181,192.168.11.142:2181,192.168.11.143:2181";
    //  计数器对象
    CountDownLatch countDownLatch = new CountDownLatch(1);
    //  用户生成序号的节点
    String defaultPath = "/uniqueId";
    //  连接对象
    ZooKeeper zooKeeper;

    @Override
    public void process(WatchedEvent event) {
        try {
            // 捕获事件状态
            if (event.getType() == Watcher.Event.EventType.None) {
                if (event.getState() == Watcher.Event.KeeperState.SyncConnected) {
                    System.out.println("连接成功");
                    countDownLatch.countDown();
                } else if (event.getState() == Watcher.Event.KeeperState.Disconnected) {
                    System.out.println("连接断开!");
                } else if (event.getState() == Watcher.Event.KeeperState.Expired) {
                    System.out.println("连接超时!");
                    // 超时后服务器端已经将连接释放,需要重新连接服务器端
                    zooKeeper = new ZooKeeper(IP, 6000,
                            new GloballyUniqueId());
                } else if (event.getState() == Watcher.Event.KeeperState.AuthFailed) {
                    System.out.println("验证失败!");
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    // 构造方法
    public GloballyUniqueId() {
        try {
            //打开连接
            zooKeeper = new ZooKeeper(IP, 5000, this);
            // 阻塞线程,等待连接的创建成功
            countDownLatch.await();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    // 生成id的方法
    public String getUniqueId() {
        String path = "";
        try {
            //创建临时有序节点
            path = zooKeeper.create(defaultPath, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        // /uniqueId0000000001
        return path.substring(9);   // 0000000001
    }

    public static void main(String[] args) {
        GloballyUniqueId globallyUniqueId = new GloballyUniqueId();
        for (int i = 1; i <= 5; i++) {
            String id = globallyUniqueId.getUniqueId();
            System.out.println(id);
        }
    }
}

我们可以模拟出多个客户端进行测试

只要所有的客户端连接的是同一个zookeeper,那么在zk上面创建的临时有序节点就会按照顺序创建,即使比如客户端1执行了zookeeper.close方法,zookeeper也只是将创建的00000001,00000004,00000008临时节点进行删除,编号还是从00000010开始。

注意上述代码是线程安全的,因为zk的特点就是为每一个操作生成唯一的事务id,zk会严重按照事务id顺序执行。 

五、利用zookeeper生成分布式锁

什么是分布式锁:假设有3个对象分别是01,02,03,一个共享资源test表。当01访问test表时首先向分布式锁申请访问权限,分布式锁看到目前test表没有人操作则允许01访问test表,并对test表上锁,同一时刻当02想对test表修改时首先向分布式锁申请权限,此时分布式锁发现test表正在被01所访问,且01并没有释放锁,因此不允许02访问,同理03申请也不允许,02、03需要等待01操作完才可访问test,保证了数据的一致性。

package com.zxy.zookeeper;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class MyLock {
    //  zk的连接串
    String IP = "192.168.11.141:2181,192.168.11.142:2181,192.168.11.143:2181";
    //  计数器对象
    CountDownLatch countDownLatch = new CountDownLatch(1);
    //ZooKeeper配置信息
    ZooKeeper zooKeeper;
    private static final String LOCK_ROOT_PATH = "/Locks";
    private static final String LOCK_NODE_NAME = "Lock_";
    private String lockPath; // 存储创建的临时有序节点路径

    // 打开zookeeper连接
    public MyLock() {
        try {
            zooKeeper = new ZooKeeper(IP, 5000, new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    if (event.getType() == Event.EventType.None) {
                        if (event.getState() == Event.KeeperState.SyncConnected) {
                            System.out.println("连接成功!");
                            countDownLatch.countDown();
                        }
                    }
                }
            });
            countDownLatch.await();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    //获取锁
    public void acquireLock() throws Exception {
        //创建锁节点
        createLock();
        //尝试获取锁
        attemptLock();
    }

    //创建锁节点
    private void createLock() throws Exception {
        //判断Locks是否存在,不存在创建
        Stat stat = zooKeeper.exists(LOCK_ROOT_PATH, false);
        if (stat == null) {
            zooKeeper.create(LOCK_ROOT_PATH, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
        // 创建临时有序节点
        lockPath = zooKeeper.create(LOCK_ROOT_PATH + "/" + LOCK_NODE_NAME, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        System.out.println("节点创建成功:" + lockPath);
    }

    //监视器对象,监视上一个节点是否被删除
    Watcher watcher = new Watcher() {
        @Override
        public void process(WatchedEvent event) {
            if (event.getType() == Event.EventType.NodeDeleted) {
                synchronized (this) {
                    notifyAll();
                }
            }
        }
    };

    //尝试获取锁
    private void attemptLock() throws Exception {
        // 获取Locks节点下的所有子节点
        List<String> list = zooKeeper.getChildren(LOCK_ROOT_PATH, false);
        // 对子节点进行排序
        Collections.sort(list);
        // /Locks/Lock_000000001
        int index = list.indexOf(lockPath.substring(LOCK_ROOT_PATH.length() + 1));
        if (index == 0) {
            System.out.println("获取锁成功!");
            return;
        } else {
            // 上一个节点的路径
            String path = list.get(index - 1);
            Stat stat = zooKeeper.exists(LOCK_ROOT_PATH + "/" + path, watcher);
            if (stat == null) {
                attemptLock();
            } else {
                synchronized (watcher) {
                    watcher.wait();
                }
                attemptLock();
            }
        }

    }

    //释放锁
    public void releaseLock() throws Exception {
        //删除临时有序节点
        zooKeeper.delete(this.lockPath,-1);
        zooKeeper.close();
        System.out.println("锁已经释放:"+this.lockPath);
    }
}
package com.zxy.zookeeper;

// 测试类
public class TicketSeller {

    private void sell(){
        System.out.println("售票开始");
        // 线程随机休眠数毫秒,模拟现实中的费时操作
        int sleepMillis = 5000;
        try {
            //代表复杂逻辑执行了一段时间
            Thread.sleep(sleepMillis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("售票结束");
    }

    public void sellTicketWithLock() throws Exception {
        MyLock lock = new MyLock();
        // 获取锁
        lock.acquireLock();
        sell();
        //释放锁
        lock.releaseLock();
    }
    public static void main(String[] args) throws Exception {
        TicketSeller ticketSeller = new TicketSeller();
        for(int i=0;i<10;i++){
            ticketSeller.sellTicketWithLock();
        }
    }
}

同时开启多个客户端执行:

六、zookeeper开源客户端curator

curator框架在zookeeper原生API接口上进行了包装,解决了很多zookeeper客户端非常底层的细节问题。提供zookeeper各种应用场景(比如分布式锁,集群leader选举,共享计数器,缓存机制,分布式队列等)的抽象封装,实现了Fluent风格(就是xxx().xxxx().xxxxx().xxxxx(),流式编程风格)的API接口。

原生zookeeperAPI的不足:连接对象异步创建,需要开发人员自行编码等待;连接没有自动重连超时机制;watcher一次注册生效一次;不支持递归创建树形节点。

curator的特点:解决session话超时重连问题;watcher可以反复注册;简化开发API;遵循Fluent风格的API;提供了分布式锁服务,共享计数器,缓存机制等等功能的抽象封装,直接哪来用即可。

首先下载curator所需要的jar包:

curator-client-5.1.0.jar

curator-framework-5.1.0.jar

curator-recipes-5.1.0.jar

slf4j-api-1.7.25.jar

zookeeper-3.6.0.jar

zookeeper-jute-3.6.0.jar

下载地址:https://mvnrepository.com/

注意市面上所有第三方框架的jar包都可以在上述地址下载:

全部下载好以后,整合到项目中就可以使用了。

1、常见curator API

(1)连接zookeeper

如果出现以下报错说明缺少selenium-server-standalone的jar包:

下载地址:https://selenium-release.storage.googleapis.com/index.html

在curator中提供了4种常见的重连策略,分别是:RetryPolicy下面的四个实现类

        new RetryOneTime(3000) : 3s后重连一次,只重连一次

        new RetryNtimes(3,3000):每3s重连一次,重连三次

        new RetryUntilElapsed(10000,3000):每3s重连一次,总等待时间超过10s停止重连

        new ExponentialBackoffRety(baseSleepTimeMs:1000,maxRetries:3):maxRetries表示会重连三次,每次重连的间隔为baseSleepTimeMs * Math.max(1, random.nextInt(1 << (retryCount + 1))),这种策略的特点是随着重连次数的增加,重连间隔会变长。

(2)新增节点

注意:.forPath必须放最后面。 

(3)更新节点

修改命名空间为set后,再开始测试:

(4)删除节点

修改命名空间为delete后,再开始测试:

(5)查看节点

修改命名空间为get后,再开始测试:

(6)查看子节点

不设置命名空间,使用上述/get节点测试:

(7)判断节点是否存在

设置命名空间为get后,再开始测试:目前/get目录下只有node1,node2子节点。

2、curator的Watcher API(监听机制)

curator提供两种Cache(Watcher)来监听节点的变化:

        NodeCache类 : 监听某个节点的变化(NodeCreate,NodeDataChanged,NodeDelete)

        PathChildrenCache类:监听某个znode的子节点的变化(子节点NodeCreate,子节点NodeDeleted,子节点NodeDataChanged)

curator创建的监听器对象不是一次性的,可以重复监听。

cacheData:表示是否能够获取到子节点的数据,true表示如果监听到子节点变化,同时还可以获取子节点的数据。一般设置为true即可。

当cacheData为false后,再次创建/watcher1/node1 "node1":

3、curator的事务

事务的核心:程序要么全部执行,要么全部不执行

我们可以自己指定事务的开始和结束:

4、curator的分布式锁

curator封装了两种分布式锁:InterProcessMutex类(排它锁,只要上锁禁止任何其他客户端再上锁,又称为写锁),InterProcessReadWriteLock(读写锁,通过获得的读写锁对象分别可以获得读锁,和写锁)。对共享资源加了写锁后不允许其他任何客户端再加任何锁,对共享资源加了读锁后只允许其他客户添加读锁。

开启两个lock2客户端,可以同时加锁。先开启lock2然后开启lock3,lock2加了读锁后不允许其他客户端加写锁。先启动lock3,任务没有执行完成之前不允许任何其他客户端加任何锁。

七、zookeeper的监控命令详解

zookeeper支持一些监控命令,通过这些命令可以获得zookeeper服务的当前状态及相关信息。用户在linux下通过执行nc命令向zookeeper提交相应的监控命令,然后zookeeper会反馈一下相关信息。

# telnet命令

telnet是一个远程登录命令,可以通过它远程登录来控制别的计算机,telnet因为采用明文传送报文,安全性不好,很多Linux服务器都不开放telnet服务,而改用更安全的ssh方式了。目前telnet命令一般不用于远程连接了,一般是用于查看某个服务的相关信息。

yum -y install telnet        # 安装telnet

telnet ip 端口                  # 远程连接指定服务器的指定端口

通过该命令也可以得到zk的状态但不太好用(不推荐使用)

# nc命令

安装:wget http://vault.centos.org/6.6/os/x86_64/Packages/nc-1.84-22.e16.x86_64.rpm

rpm -iUv nc-1.84-22.e16.x86_64.rpm

使用:echo 监控命令 | nc zk地址 2181

如果出现以下错误:

需要在zoo.cfg文件中添加41w.commands.whitelist=* 

还需要对zkServer.sh进行配置,然后重启zk服务器:

ZOOMAIN="-Dzookeeper.41w.commands.whitelist=*${ZOOMAIN}"

(1)conf命令

显示zk的配置信息,就是zoo.cfg中记录的配置信息:

(2)cons命令

显示所有连接当前zk服务器的客户端(会话)信息。

(3)crst、dump、envi命令

crst命令会重置与当前zk服务器连接的所有客户端会话信息:

dump命令用于显示所有连接到zk服务器的客户端会话id,以及各个客户端创建的临时节点路径:

envi命令显示当前zk服务器的环境配置信息:

(4)ruok、stat、srvr、srst命令

ruok命令可以测试zk服务器的运行状态:imok表示运行正常

stat命令可以显示zk服务器的详细信息:

srvr命令与stat类似:srvr不显示Clients

srst命令可以重置当前zk服务器的统计信息:

(5)wchs、wchc、wchp命令

wchs命令可以列出当前服务器上的相应监听信息:

首先创建两个客户端连接同一个zk服务器,然后在每个客户端上分别注册一个监听器。

wchc命令可以列出当前服务器上的相应监听信息,监听信息按照会话分组:首先创建两个客户端连接同一个zk服务器,然后在每个客户端上分别注册两个监听器监听两个节点。

wchp命令与wchc命令很相似,可以列出当前服务器上的相应监听信息,监听信息按照路径分组。

(6)mntr命令

mntr命令与stat相似,可以显示服务器的详细信息(健康状态)

在新版zookeeper中,上述四字命令显示的信息更多。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值