zoukankan      html  css  js  c++  java
  • ZooKeeper学习第三期---Zookeeper命令操作

    ZooKeeper学习第一期---Zookeeper简单介绍

    ZooKeeper学习第二期--ZooKeeper安装配置 

    ZooKeeper学习第三期---Zookeeper命令操作

    ZooKeeper学习第四期---构建ZooKeeper应用

    ZooKeeper学习第五期--ZooKeeper管理分布式环境中的数据

    ZooKeeper学习第六期---ZooKeeper机制架构

    ZooKeeper学习第七期--ZooKeeper一致性原理

    ZooKeeper学习第八期——ZooKeeper伸缩性

    一、Zookeeper的四字命令

    Zookeeper支持某些特定的四字命令字母与其的交互。他们大多数是查询命令,用来获取Zookeeper服务的当前状态及相关信息。用户在客户端可以通过telnet或nc向Zookeeper提交相应的命令。Zookeeper常用的四字命令见下图所示。

    通过下列命令来获取这些监控信息 echo commands  |  nc ip port

    如:

    echo conf | nc 192.168.144.110 2181  

    上图,是Zookeeper四字命令的一个简单用例。

    [root@hadoop ~]# echo ruok|nc localhost 2181
    [root@hadoop ~]# zkServer.sh start zoo1.cfg
    JMX enabled by default
    Using config: /usr/local/zk/bin/../conf/zoo1.cfg
    Starting zookeeper ... STARTED
    [root@hadoop ~]#  zkServer.sh start zoo2.cfg
    JMX enabled by default
    Using config: /usr/local/zk/bin/../conf/zoo2.cfg
    Starting zookeeper ... STARTED
    [root@hadoop ~]#  zkServer.sh start zoo3.cfg
    JMX enabled by default
    Using config: /usr/local/zk/bin/../conf/zoo3.cfg
    Starting zookeeper ... STARTED
    [root@hadoop ~]# echo ruok|nc localhost 2181
    imok[root@hadoop ~]# echo ruok|nc localhost 2182
    imok[root@hadoop ~]# echo ruok|nc localhost 2183
    imok[root@hadoop ~]# echo conf|nc localhost 2181
    clientPort=2181
    dataDir=/usr/local/zk/data_1/version-2
    dataLogDir=/usr/local/zk/logs_1/version-2
    tickTime=2000
    maxClientCnxns=60
    minSessionTimeout=4000
    maxSessionTimeout=40000
    serverId=0
    initLimit=10
    syncLimit=5
    electionAlg=3
    electionPort=3387
    quorumPort=2287
    peerType=0
    [root@hadoop ~]#

     

    额:

    yum install nc

     

    二、Zookeeper的简单操作

    2.1  Zookeeper的shell操作

    2.1.1 Zookeeper命令工具

    再启动Zookeeper服务之后,输入以下命令,连接到Zookeeper服务:

    zkCli.sh -server localhost:2181

    连接成功之后,系统会输出Zookeeper的相关环境及配置信息,并在屏幕输出“welcome to Zookeeper!”等信息。输入help之后,屏幕会输出可用的Zookeeper命令,如下图所示

     

    2.1.2 使用Zookeeper命令的简单操作步骤

    (1) 使用ls命令查看当前Zookeeper中所包含的内容:ls /

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

    (2) 创建一个新的Znode节点"zk",以及和它相关字符,执行命令:create /zk myData

    [zk: localhost:2181(CONNECTED) 2] create /zk myData
    Created /zk

    (3) 再次使用ls命令来查看现在Zookeeper的中所包含的内容:ls /

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

    此时看到,zk节点已经被创建。  

    (4) 使用get命令来确认第二步中所创建的Znode是否包含我们创建的字符串,执行命令:get /zk

    [zk: localhost:2181(CONNECTED) 4] get /zk
    myData
    cZxid = 0x500000006
    ctime = Fri Oct 17 03:54:20 PDT 2014
    mZxid = 0x500000006
    mtime = Fri Oct 17 03:54:20 PDT 2014
    pZxid = 0x500000006
    cversion = 0
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 6
    numChildren = 0

    (5) 接下来通过set命令来对zk所关联的字符串进行设置,执行命令:set /zk jiang1234

    [zk: localhost:2181(CONNECTED) 5] set /zk jiang2014
    cZxid = 0x500000006
    ctime = Fri Oct 17 03:54:20 PDT 2014
    mZxid = 0x500000007
    mtime = Fri Oct 17 03:55:50 PDT 2014
    pZxid = 0x500000006
    cversion = 0
    dataVersion = 1
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 9
    numChildren = 0

    (6) 再次使用get命令来查看,上次修改的内容,执行命令:get /zk

    [zk: localhost:2181(CONNECTED) 6] get /zk
    jiang2014
    cZxid = 0x500000006
    ctime = Fri Oct 17 03:54:20 PDT 2014
    mZxid = 0x500000007
    mtime = Fri Oct 17 03:55:50 PDT 2014
    pZxid = 0x500000006
    cversion = 0
    dataVersion = 1
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 9
    numChildren = 0

    (7) 下面我们将刚才创建的Znode删除,执行命令:delete /zk

    [zk: localhost:2181(CONNECTED) 7] delete /zk

    (8) 最后再次使用ls命令查看Zookeeper中的内容,执行命令:ls /

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

    经过验证,zk节点已经删除。

    2.2 Zookeeper的api的简单使用

    2.2.1 ZookeeperAPI简介

    Zookeeper API共包含五个包,分别为:

      (1)org.apache.zookeeper
      (2)org.apache.zookeeper.data
      (3)org.apache.zookeeper.server
      (4)org.apache.zookeeper.server.quorum
      (5)org.apache.zookeeper.server.upgrade

    其中org.apache.zookeeper,包含Zookeeper类,他是我们编程时 最常用的类文件。这个类是Zookeeper客户端的主要类文件。如果要使用Zookeeper服务,应用程序首先必须创建一个Zookeeper实例, 这时就需要使用此类。一旦客户端和Zookeeper服务建立起了连接,Zookeeper系统将会给次连接会话分配一个ID值,并且客户端将会周期性的 向服务器端发送心跳来维持会话连接。只要连接有效,客户端就可以使用Zookeeper API来做相应处理了。

    Zookeeper类提供了如下图所示的几类主要方法

     

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

    三、ZooKeeper示例

    假设一组服务器,用于为客户端提供一些服务。我们希望每个客户端都能够能够找到其中一台服务器,使其能够使用这些服务,挑战之一就是维护这组服务器 列表。这组服务器的成员列表明显不能存在网络中的单个节点上,因为如果那个节点发生故障,就意味着是整个系统的故障(我们希望这个列表有很高的可用性)。 假设我们有了一个可靠的方法解决了这个成员列表的存储问题。如果其中一台服务器出现故障,我们仍然需要解决如何从服务器成员列表中将它删除的问题。某个进 程需要负责删除故障服务器,但注意不能由故障服务器自己来完成,因为故障服务器已经不再运行。

    我们所描述的不是一个被动的分布式数据结构,而是一个主动的、能够在某个外部事件发生时修改数据项状态的数据结构。ZooKeeper提供这种服务,所以让我们看看如何使用它来实现这种众所周知的组成员管理应用。

    ZooKeeper中的组成员关系

    理解ZooKeeper的一种方法就是将其看作一个具有高可用性的文件系统。但这个文件系统中没有文件和目录,而是统一使用“节点”(node)的概念,称为znode。znode既可以作为保存数据的容器(如同文件),也可以作为保存其他znode的容器(如同目录)。所有的znode构成一个层次化的命名空间。一种自然的建立组成员列表的方式就是利用这种层次结构,创建一个以组名为节点名的znode作为父节点,然后以组成员名(服务器名)为节点名来创建作为子节点的znode。如下图给出了一组具有层次结构的znode。

     

    在这个示例中,我们没有在任何znode中存储数据,但在一个真实的应用中,你可以将“关于成员的数据”存储在它们的znode中,例如主机名。

    3.1 创建组

    3.1.1 代码示例

    让我们通过编写一段程序的方式来再次详细介绍ZooKeeper的Java API,这段示例程序用于为组名为/zoo的组创建一个znode。代码参见如下

    代码 该程序在ZooKeeper中新建表示组的Znode

    package zk;
    
    import java.io.IOException;
    import java.util.concurrent.CountDownLatch;
    
    import org.apache.zookeeper.CreateMode;
    import org.apache.zookeeper.KeeperException;
    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 CreateGroup implements Watcher{
        
        private static final int SESSION_TIMEOUT=5000;
        private static final String HOST1="192.168.56.90:2181";
        private static final String HOST2="192.168.56.90:2182,192.168.56.90:2183,192.168.56.90:2184";
        
        
        
        private ZooKeeper zk;
        private CountDownLatch connectedSignal=new CountDownLatch(1);
    
        public void process(WatchedEvent event) {
            if(event.getState()==KeeperState.SyncConnected){
                connectedSignal.countDown();
            }
        }
        
        public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
            CreateGroup createGroup = new CreateGroup();
            createGroup.connect(HOST2);
            createGroup.create("c");
            createGroup.close();
        }
    
        private void close() throws InterruptedException {
            zk.close();
        }
    
        private void create(String groupName) throws KeeperException, InterruptedException {
            String path="/"+groupName;
            if(zk.exists(path, false)== null){
                zk.create(path, null/*data*/, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
            System.out.println("Created:"+path);
        } 
    
        private void connect(String hosts) throws IOException, InterruptedException {
            zk = new ZooKeeper(hosts, SESSION_TIMEOUT, this);
            connectedSignal.await();
        }
    }

     运行结果

     

    断点时候发现

    State:CONNECTED,假如连接不成功会是State:CONNECTING

    3.1.2 代码分析

    在上面代码中,main()方法执行时,创建了一个CreateGroup实例并且调用了这个实例的connect()方法。connect方法实例化了一个新的ZooKeeper类的对象,这个类是客户端API中的主要类,并且负责维护客户端和ZooKeeper服务之间的连接。ZooKeeper类的构造函数有三个参数:
      第一个是:ZooKeeper服务的主机地址,可指定端口,默认端口是2181。
      第二个是:以毫秒为单位的会话超时参数,这里我们设成5秒。
      第三个是:参数是一个Watcher对象的实例。
    Watcher对象接收来自于ZooKeeper的回调,以获得各种事件的通知。在这个例子中,CreateGroup是一个Watcher对象,因此我们将它传递给ZooKeeper的构造函数。
    当一个ZooKeeper的实例被创建时,会启动一个线程连接到ZooKeeper服务。由于对构造函数的调用是立即返回的,因此在使用新建的ZooKeeper对象之前一定要等待其与ZooKeeper服务之间的连接建立成功。我们使用Java的CountDownLatch类来阻止使用新建的ZooKeeper对象,直到这个ZooKeeper对象已经准备就绪。这就是Watcher类的
    用途,在它的接口中只有一个方法:
        public void process(WatcherEvent event);
    客 户端已经与ZooKeeper建立连接后,Watcher的process()方法会被调用,参数是一个表示该连接的事件。在接收到一个连接事件(由 Watcher.Event.KeeperState的枚举型值SyncConnected来表示)时,我们通过调用CountDownLatch的countDown()方法来递减它的计数器。锁存器(latch)被创建时带有一个值为1的计数器,用于表示在它释放所有等待线程之前需要发生的事件数。在调用一欢countDown()方法之后,计数器的值变为0,则await()方法返回。
    现在connect()方法已经返回,下一个执行的是CreateGroup的create()方法。在这个方法中,我们使用ZooKeeper实例中的create()方法来创建一个新的ZooKeeper的znode。所需的参数包括:
        路径:用字符串表示。
        znode的内容:字节数组,本例中使用空值。
        访问控制列表:简称ACL,本例中使用了完全开放的ACL,允许任何客户端对znode进行读写。
        创建znode的类型:有两种类型的znode:短暂的和持久的。

    创建znode的客户端断开连接时,无论客户端是明确断开还是因为任何原因而终止,短暂znode都会被ZooKeeper服务删除。与之相反,当 客户端断开连接时,持久znode不会被删除。我们希望代表一个组的znode存活的时间应当比创建程序的生命周期要长,因此在本例中我们创建了一个持久 的znode。

    create()方法的返回值是ZooKeeper所创建的路径,我们用这个返回值来打印一条表示路径成功创建的消息。当我们查看“顺序znode”(sequential znode)时.会发现create()方法返回的路径与传递给该方法的路径不同。

     !把HOST1改成HOST2

        public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
            CreateGroup createGroup = new CreateGroup();
            createGroup.connect(HOST2);
            createGroup.create("c");
            createGroup.close();
        }

    192.168.56.90:2182,

    192.168.56.90:2183,

    192.168.56.90:2184

    的节点上都有 /c 节点,数据一致性 

    断点发现

     

    实例是leader

    3.2 加入组

    下面的这一段程序用于注册组的成员。每个组成员将作为一个程序运行,并且加入到组中。当程序退出时,这个组成员应当从组中被删除。为了实现这一点,我们在ZooKeeper的命名空间中使用短暂znode来代表一个组成员。

    在基类ConnectionWatcher中,对创建和连接ZooKeeper实例的程序逻辑进行了重构,参见代码如下

    代码 用于将成员加入组的程序

    package zk;
    
    
    import java.io.IOException;
    import java.util.concurrent.CountDownLatch;
    
    import org.apache.zookeeper.WatchedEvent;
    import org.apache.zookeeper.Watcher;
    import org.apache.zookeeper.Watcher.Event.KeeperState;
    import org.apache.zookeeper.ZooKeeper;
    
    public class ConnectionWatcher implements Watcher{
        
        private static final int SESSION_TIMEOUT=5000;
        
        
        protected ZooKeeper zk;
        CountDownLatch connectedSignal=new CountDownLatch(1);
        
        public void connect(String host) throws IOException, InterruptedException{
            zk=new ZooKeeper(host, SESSION_TIMEOUT, this);
            connectedSignal.await();
        }
    
        public void process(WatchedEvent event) {
            if(event.getState()==KeeperState.SyncConnected){
                connectedSignal.countDown();
            }
        }
        public void close() throws InterruptedException{
            zk.close();
        }
    
    }
    package zk;
    
    import java.io.IOException;
    
    import org.apache.zookeeper.CreateMode;
    import org.apache.zookeeper.KeeperException;
    import org.apache.zookeeper.ZooDefs.Ids;
    
    
    public class JoinGroup extends ConnectionWatcher{
        
        private static final String HOST1="192.168.56.90:2181";
        private static final String HOST2="192.168.56.90:2182,192.168.56.90:2183,192.168.56.90:2184";
        
        public void join(String groupName,String memberName) throws KeeperException, InterruptedException{
            String path="/"+groupName+"/"+memberName;
            String createdPath=zk.create(path, null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
            System.out.println("Created:"+createdPath);
        }
        public static void main(String[] args) throws InterruptedException, IOException, KeeperException {
            JoinGroup joinGroup = new JoinGroup();
            joinGroup.connect(HOST1);
            joinGroup.join("a", "aa");
            Thread.sleep(Long.MAX_VALUE);
        }
        
    
    }

    JoinGroup的代码与CreateGroup非常相似,在它的join()方法中,创建短暂znode,作为组znode的子节点,然后通过 休眠来模拟正在做某种工作,直到该进程被强行终止。接着,你会看到随着进程终止,这个短暂znode被ZooKeeper删除。

    3.3 列出组成员

    现在,我们需要一段程序来查看组成员,参见代码如下:

    代码 用于列出组成员的程序

    package zk;
    
    import java.io.IOException;
    import java.util.Iterator;
    import java.util.List;
    
    import org.apache.zookeeper.KeeperException;
    
    public class ListGroup extends ConnectionWatcher {
        
        private static final String HOST1="192.168.56.90:2181";
        private static final String HOST2="192.168.56.90:2182,192.168.56.90:2183,192.168.56.90:2184";
        
        public void list(String groupNmae) throws KeeperException, InterruptedException{
            String path ="/"+groupNmae;
            try {
                List children = zk.getChildren(path, false);
                if(children.isEmpty()){
                    System.out.println("Group "+groupNmae+" does not exist 
    ");
                    System.exit(1);
                }
                Iterator it=children.iterator();
                while(it.hasNext()){
                    String child=(String)it.next();
                    System.err.println(child);
                }
            } catch (KeeperException.NoNodeException e) {
                System.out.println("Group "+groupNmae+" does not exist 
    ");
                System.exit(1);
            } 
        }
        public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
            ListGroup listGroup = new ListGroup();
            listGroup.connect(HOST2);
            listGroup.list("");
            listGroup.close();
        }
    }

    在list()方法中,我们调用了getChildren()方法来检索并打印输出一个znode的子节点列表,调用参数为:该znode的路径和 设为false的观察标志。如果在一znode上设置了观察标志,那么一旦该znode的状态改变,关联的观察(Watcher)会被触发。虽然在这里我 们可以不使用观察,但在查看一个znode的子节点时,也可以设置观察,让应用程序接收到组成员加入、退出和组被删除的有关通知。

    3.4 删除组

    下面来看如何删除一个组。ZooKeeper类提供了一个delete()方法,该方法有两个参数:

    1. 路径

    2. 版本号

    如果所提供的版本号与znode的版本号一致,ZooKeeper会删除这个znode。这是一种乐观的加锁机制,使客户端能够检测出对znode的修改冲突。通过将版本号设置为-1,可以绕过这个版本检测机制,不管znode的版本号是什么而直接将其删除。ZooKeeper不支持递归的删除操作,因此在删除父节点之前必须先删除子节点。

    在代码3.5中,DeleteGroup类用于删除一个组及其所有成员。
    代码3.5用于删除一个组及其所有成员的程序

    package zk;
    
    import java.io.IOException;
    import java.util.Iterator;
    import java.util.List;
    
    import org.apache.zookeeper.KeeperException;
    
    public class DeleteGroup extends ConnectionWatcher{
        
        private static final String HOST1="192.168.56.90:2181";
        private static final String HOST2="192.168.56.90:2182,192.168.56.90:2183,192.168.56.90:2184";
        
        public void delete(String groupName) throws InterruptedException, KeeperException{
            String path="/"+groupName;
            List children;
            try {
                children = zk.getChildren(path, false);
                Iterator it=children.iterator();
                while(it.hasNext()){
                    zk.delete(path+"/"+(String)it.next(), -1); 
                }
    
                zk.delete(path, -1);
            } catch (KeeperException.NoNodeException e) {
                System.out.println("Group "+groupName+" does not exist 
    ");
                System.exit(1);
            }    
        }
        public static void main(String[] args) throws InterruptedException, IOException, KeeperException {
            DeleteGroup deleteGroup = new DeleteGroup();
            deleteGroup.connect(HOST1);
            deleteGroup.delete("a");
            deleteGroup.close();
        }
    }

    最后,我们可以删除之前所创建的组:

  • 相关阅读:
    [转载]读史札记21:出局依然是英雄
    关于 Delphi 中窗体的停靠
    关于 Indy 的发送与接收 及 不定长度流的见解
    基于Indy10 ,TCPIP 聊天示例
    opera 去除标题栏,最大化窗口代码
    第二篇 《XML 类化生成工具》
    第一篇《后缀表达式》
    多线程操作一例:查找 pas dfm 里的中文
    关于批量执行SQL语句
    Erlang 学习笔记 (一)
  • 原文地址:https://www.cnblogs.com/crazylqy/p/7130860.html
Copyright © 2011-2022 走看看