zoukankan      html  css  js  c++  java
  • 第8章 ZooKeeper操作

    8.1 集群环境搭建

    【操作目的】
    由于在ZooKeeper集群中,会有一个Leader服务器负责管理和协调其他集群服务器,因此服务器的数量通常都是单数,例如3,5,7...等,这样数量为2n+1的服务器就可以允许最多n台服务器的失效。
    【操作步骤】
    本例中,我们仍然使用三个节点搭建部署ZooKeeper集群,搭建步骤如下:

    1.上传ZooKeeper安装文件

    在centos01节点中,上传ZooKeeper安装文件zookeeper-3.4.9.tar.gz到目录/opt/softwares/中,并将其解压到目录/opt/modules/,解压命令如下:

    tar -zxvf zookeeper-3.4.9.tar.gz -C /opt/modules/
    

    2.编写配置文件

    (1)在ZooKeeper安装目录下新建文件夹dataDir,用于存放ZooKeeper数据。
    (2)在ZooKeeper安装目录下的conf文件夹中新建配置文件zoo.cfg,加入以下内容:

    tickTime=2000
    initLimit=10
    syncLimit=5
    dataDir=/opt/modules/zookeeper-3.4.9/dataDir
    clientPort=2181
    
    server.1=centos01:2888:3888
    server.2=centos02:2888:3888
    server.3=centos03:2888:3888
    

    上述参数说明如下:
    initLimit:集群中的Follower服务器初始化连接Leader服务器时能等待的最大心跳数(连接超时时长)。默认为10,即如果经过10个心跳之后Follower服务器仍然没有收到Leader服务器的返回信息,则连接失败。本例中该参数值为5,参数tickTime为2000,则连接超时时长为52000=10秒(即tickTimeinitLimit=10秒)。
    syncLimit:集群中的Follower服务器与Leader服务器之间发送消息以及请求/应答时所能等待的最多心跳数。本例中,tickTime的值为2,时长为2*2000=4秒。
    server.id:标识不同的ZooKeeper服务器。ZooKeeper可以从“server.id=host:port1:port2”中读取相关信息。其中,id值必须在整个集群中是唯一的,且大小在1到255之间;host是服务器的名称或IP地址;第一个端口(port1)是Leader端口,即该服务器作为Leader时供Follower连接的端口;第二个端口(port2)是选举端口,即选举Leader服务器时供其它Follower连接的端口。
    dataDir:ZooKeeper保存数据的目录。
    clientPort:客户端连接ZooKeeper服务器的端口,ZooKeeper会监听这个端口,接收客户端的请求。
    (3)在配置文件zoo.cfg中的参数dataDir指定的目录下(此处为ZooKeeper安装目录下的dataDir文件夹)新建一个名为myid的文件,这个文件仅包含一行内容,即当前服务器的id值,与参数server.id中的id值相同。本例中,当前服务器(centos01)的id值为1,则应该在myid文件中写入数字1。ZooKeeper启动时会读取该文件,将其中的数据与zoo.cfg里写入的配置信息进行对比,从而获取当前服务器的身份信息。

    3.拷贝ZooKeeper安装信息到其它节点

    centos01节点安装完成后,需要拷贝整个ZooKeeper安装目录到centos02和centos03节点,命令如下:

    scp -r /opt/modules/zookeeper-3.4.9/ hadoop@centos02:/opt/modules/
    scp -r /opt/modules/zookeeper-3.4.9/ hadoop@centos03:/opt/modules/
    

    4.修改其它节点配置

    拷贝完成后,需要将centos02和centos03节点中的myid文件的值修改为对应的数字,即作出以下操作:
    修改centos02节点中的opt/modules/zookeeper-3.4.9/dataDir/myid文件中的值为2。
    修改centos03节点中的opt/modules/zookeeper-3.4.9/dataDir/myid文件中的值为3。

    5.启动ZooKeeper

    分别进入每个节点的ZooKeeper安装目录,执行如下命令:

    bin/zkServer.sh start
    

    输出以下信息代表启动成功:
    ZooKeeper JMX enabled by default
    Using config: /usr/local/zookeeper-3.4.9/bin/../conf/zoo.cfg
    Starting zookeeper ... STARTED

    需要注意的是,每台服务器都要执行一遍启动命令,这样才能使得整个集群启动起来。

    6.查看启动状态

    分别在各个节点上执行如下命令,查看ZooKeeper服务的状态:

    bin/zkServer.sh status
    

    在centos01节点上查看服务状态,输出了以下信息:
    ZooKeeper JMX enabled by default
    Using config: /usr/local/zookeeper-3.4.9/bin/../conf/zoo.cfg
    Mode: follower

    在centos02服务器上查看服务状态,输出了以下信息:
    ZooKeeper JMX enabled by default
    Using config: /usr/local/zookeeper-3.4.9/bin/../conf/zoo.cfg
    Mode: follower

    在centos03服务器上查看服务状态,输出了以下信息:
    ZooKeeper JMX enabled by default
    Using config: /usr/local/zookeeper-3.4.9/bin/../conf/zoo.cfg
    Mode: leader

    由此可见,本例中centos03服务器上的ZooKeeper服务为Leader,其余两个ZooKeeper服务为Follower。
    如果在查看启动状态时输出以下信息,说明ZooKeeper集群启动不成功,出现错误。
    Error contacting service. It is probably not running.
    此时需要修改bin/zkEvn.sh文件中的以下内容,将错误信息输出到日志文件。

    if [ "x${ZOO_LOG4J_PROP}" = "x" ]  
    then  
        ZOO_LOG4J_PROP="INFO,CONSOLE"  
    fi  
    

    将上述内容中的CONSOLE改为ROLLINGFILE,修改后的内容如下:

    if [ "x${ZOO_LOG4J_PROP}" = "x" ]  
    then  
        ZOO_LOG4J_PROP="INFO,ROLLINGFILE"  
    fi  
    

    修改后,重新启动ZooKeeper集群,查看在ZooKeeper安装目录下生成的日志文件zookeeper.log,发现报以下错误:
    java.net.NoRouteToHostException: 没有到主机的路由。
    产生上述错误的原因是,系统没有关闭防火墙,导致ZooKeeper集群间连接不成功。因此需要关闭系统防火墙(为了防止出错,在最初的集群环境配置的时候可以直接将防火墙关闭),CentOS7关闭防火墙的命令如下:

    systemctl stop firewalld.service
    systemctl disable firewalld.service
    

    关闭各节点的防火墙后,重新启动ZooKeeper,再一次查看启动状态,发现一切正常了。

    7.测试客户端连接

    在centos01节点上(其它节点也可以),进入ZooKeeper安装目录,执行以下命令,可以连接ZooKeeper服务器,连接成功后可以输入ZooKeeper的Shell命令进行操作与测试了。

    [hadoop@centos01]$ bin/zkCli.sh -server centos01:2181
    

    8.2 命令行操作

    【操作目的】
    ZooKeeper的命令行工具类似于Shell。当ZooKeeper服务启动以后,可以在其中一台运行ZooKeeper服务的服务器中输入以下命令(需要进入ZooKeeper安装目录),启动一个客户端,连接到ZooKeeper集群:
    [hadoop@centos01]$ bin/zkCli.sh -server centos01:2181
    连接成功后,系统会输出ZooKeeper的运行环境及配置信息,并在屏幕输出“Welcome to ZooKeeper”等欢迎信息。之后就可以使用ZooKeeper命令行工具了。
    【操作步骤】
    以下是ZooKeeper命令行工具的一些简单操作示例:
    (1)使用ls命令,可以查看当前ZooKeeper中所包含的内容:

    [zk: centos01:2181(CONNECTED) 4] ls /
    [zookeeper]
    

    可以看到,当前有一个名称为zookeeper的Znode节点。
    (2)使用create命令,可以创建一个新的Znode节点。例如,创建一个名为“zk”的Znode以及在它上面存放的元数据字符串“myData”,命令及输出信息如下:

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

    (3)使用get命令,可以查看某个Znode的详细信息及其包含的元数据字符串。例如,查看Znode节点/zk的详细信息,命令及输出信息如下:

    [zk: centos01:2181(CONNECTED) 6] get /zk
    myData
    cZxid = 0x800000002
    ctime = Thu Mar 22 10:12:11 CST 2018
    mZxid = 0x800000002
    mtime = Thu Mar 22 10:12:11 CST 2018
    pZxid = 0x800000002
    cversion = 0
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 6
    numChildren = 0
    

    (4)使用set命令,可以修改Znode节点的元数据字符串。例如,将Znode节点/zk所关联的字符串修改为“myDataUpdate”,命令及输出信息如下:

    [zk: centos01:2181(CONNECTED) 10] set /zk "myDataUpdate"
    cZxid = 0x800000002
    ctime = Thu Mar 22 10:12:11 CST 2018
    mZxid = 0x800000005
    mtime = Thu Mar 22 10:18:19 CST 2018
    pZxid = 0x800000002
    cversion = 0
    dataVersion = 3
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 12
    numChildren = 0
    

    (5)使用delete命令,可以将某个Znode节点删除。例如,删除上面创建的Znode节点/zk,命令如下:

    [zk: centos01:2181(CONNECTED) 11] delete /zk
    

    使用ZooKeeper命令行工具也可以创建有层次的目录。例如,在/zk节点目录下创建新的目录node1,并关联其元数据为“nodeData”,命令及输出信息如下:

    [zk: centos01:2181(CONNECTED) 18] create /zk/node1 "nodeData"
    Created /zk/node1
    

    8.3 Java API操作

    除了可以使用命令行方式对ZooKeeper进行操作外,ZooKeeper还提供了Java API操作接口。下面对ZooKeeper的常用Java API接口进行介绍。

    8.3.1 创建Java工程

    在编写Java API之前,首先需要新建一个ZooKeeper项目。ZooKeeper项目的结构与普通的Java项目一样,只是依赖的jar包不同。
    在eclipse中新建一个Maven项目zk_demo(Maven项目的搭建此处不做过多讲解),然后在该项目的pom.xml文件中添加以下代码,以引入ZooKeeper的Java API依赖包:

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

    配置好pom.xml后,即可进行ZooKeeper Java API的编写。

    8.3.2 创建节点

    Zookeeper创建节点不支持递归调用,即无法在父节点不存在的情况下创建一个子节点,如在/zk0l节点不存在的情况下创建/zk01/ch01节点;并且如果一个节点已经存在,那么创建同名节点时,会抛出NodeExistsException异常。
    下面我们创建一个节点/ zk001,节点的元数据为“zk001_data”,步骤如下:

    1.编写代码

    在新建的zk_demo项目中新建Java类CreatePath.java,完整代码如下所示:

    import org.apache.zookeeper.CreateMode;
    import org.apache.zookeeper.ZooKeeper;
    import org.apache.zookeeper.ZooDefs.Ids;
    
    public class CreatePath {
    
    	public static void main(String[] args) throws Exception {
    		String connectStr="192.168.170.128:2181,192.168.170.129:2181,192.168.170.130:2181";
    		//参数1:服务器连接字符串
    		//参数2:连接超时时间
    		//参数3:观察者对象(回调函数)
    		ZooKeeper zk = new ZooKeeper(connectStr, 3000, null);		
    		/* 1.CreateMode 取值   
    	     *  PERSISTENT:持久化节点
    	     *  PERSISTENT_SEQUENTIAL:顺序自动编号的目录节点
    	     *  EPHEMERAL:临时目录节点,客户端断开连接时,这种节点会被自动删除 
    	     *  EPHEMERAL_SEQUENTIAL:临时自动编号节点 
    	     *  */
    		String path=zk.create("/zk001", "zk001_data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    		System.out.println(path);
    	}
    }
    

    2.程序解读

    ZooKeeper zk  = new ZooKeeper(connectStr, 3000, null);
    

    新建一个ZooKeeper对象,传入三个参数,第一个参数为以逗号分隔的服务器连接字符串,格式:“host:端口”,这里需要把所有的ZooKeeper服务器的地址都写上,而不是只写其中一台。ZooKeeper客户端对象将从连接串中挑选任意一个服务器进行连接,如果连接失败,将尝试连接另外一个服务器,直到建立连接。这样的好处是能保证ZooKeeper服务的高可靠性,防止因为其中一台机器宕机而导致连接失败。第二个参数为连接超时时间,这里是3秒。第三个参数为观察者对象,连接成功后会调用观察者对象中的回调函数,这里传入null即可。

    String path=zk.create("/zk001", "zk001_data".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    

    调用ZooKeeper对象的创建节点函数,返回创建的节点路径,并需要传入四个参数。第一个参数为节点名称。第二个参数为节点数据,需要转成字节数组。第三个参数为权限控制,这里使用ZooKeeper自带的完全开放权限Ids.OPEN_ACL_UNSAFE。第四个参数为创建模式,它是一个枚举类型,共有四个取值,PERSISTENT(持久化,这个目录节点存储的数据不会丢失 ,即客户端失去连接之后不会被自动删除)、PERSISTENT_SEQUENTIAL(顺序自动编号的目录节点,这种目录节点在命名上会根据当前已经存在的节点数自动加 1,然后将已经成功创建的目录节点名返回给客户端)、EPHEMERAL(临时目录节点,客户端断开连接时,这种节点会被自动删除)、EPHEMERAL_SEQUENTIAL(临时自动编号目录节点,客户端断开连接时,这种节点也会被自动删除)。

    3.运行程序

    直接在eclipse中右击运行该程序即可。

    8.3.3 添加数据

    我们可以通过调用ZooKeeper对象的setData()函数给节点添加数据,示例代码如下:

    @Test  
        public void setNodeData() throws Exception {  
        	String connectStr="192.168.170.128:2181,192.168.170.129:2181,192.168.170.130:2181";
        	ZooKeeper zk  = new ZooKeeper(connectStr, 3000, null);  
            Stat stat = zk.setData("/zk002", "zk002_data2".getBytes(), -1);  
            System.out.println(stat.getVersion());
        }
    

    代码解析:

    Stat stat = zk.setData("/zk002", "zk002_data2".getBytes(), -1);
    

    setData函数的第一个参数为节点路径。第二个参数为需要添加的数据,并转成字节数组。第三个参数为版本号,-1代表所有版本。

    8.3.4 获取数据

    我们可以调用ZooKeeper对象的getData()函数,获得指定节点的数据,示例代码如下:

    @Test  
        public void getNodeData() throws Exception {  
        	String connectStr="192.168.170.128:2181,192.168.170.129:2181,192.168.170.130:2181";
        	ZooKeeper zk  = new ZooKeeper(connectStr, 3000, null);  
        	Stat stat=new Stat();
    	//返回指定路径上的节点数据和节点状态,节点的状态会放入stat对象中
    	byte[] bytes=zk.getData("/zk002", null, stat);
    	System.out.println(new String(bytes));
        }
    

    上述代码获取了节点/zk002的数据,而且转成了字符串进行了输出,并将节点/zk002的状态放入了对象stat中。如需查看状态信息,可以从对象stat中进行输出查看。
    可以看到,在getData函数的第二个参数,传入的是null,也可以指定一个观察者对象watcher,对节点数据的变化进行监听,一旦有数据改变,就会触发watcher指定的回调函数。我们对上方代码加入观察者后,示例代码如下:

    @Test  
        public void getNodeDataWatch() throws Exception {  
        	String connectStr="192.168.170.128:2181,192.168.170.129:2181,192.168.170.130:2181";
        	ZooKeeper zk  = new ZooKeeper(connectStr, 3000, null);  
        	Stat stat=new Stat();
    		//返回指定路径上的节点数据和节点状态,节点的状态会放入stat对象中
    		byte[] bytes=zk.getData("/zk002", new Watcher(){
    			@Override
    			public void process(WatchedEvent event) {
    				System.out.println(event.getType());
    			}
    			
    		}, stat);
    		System.out.println(new String(bytes));
    		
    		//改变节点数据,触发watch
    		zk.setData("/zk002", "zk002_data_testwatch".getBytes(), -1); 
    		
    		//为了验证是否触发了watch,不让程序结束
    		while(true){
    			Thread.sleep(3000);
    		}
    		
        }
    

    代码分析:

    public void process(WatchedEvent event) {
    	System.out.println(event.getType());
    }
    

    process 方法是 Watcher 接口中的一个回调方法,当 ZooKeeper 向客户端发送一个 Watcher 事件通知时,客户端就会对相应的 process 方法进行回调,从而实现对事件的处理。
    process 方法包含 WatcherEvent 类型的参数,WatchedEvent 包含了每一个事件的三个基本属性:通知状态(KeeperState)、事件类型(EventType)和节点路径(Path),ZooKeeper 使用 WatchedEvent 对象来封装服务端事件并传递给 Watcher,从而方便回调方法 process 对服务端事件进行处理。
    上述代码通过System.out.println(event.getType());输出服务端的事件类型,输出结果为NodeDataChanged。从结果单词的含义可知,节点数据被改变了。

    while(true){
    	Thread.sleep(3000);
    }
    

    为了能够更好的验证是否触发了watch,不让程序一次执行到底,从而加入了上方代码,让程序一直停留在此处。

    8.3.5 删除节点

    我们可以通过调用ZooKeeper对象的delete()函数,对指定路径节点进行删除。示例代码如下:

    @Test
    	public void deletePath() throws Exception{
    		String connectStr="192.168.170.128:2181,192.168.170.129:2181,192.168.170.130:2181";
    		ZooKeeper zk  = new ZooKeeper(connectStr, 3000, null);  
    		//删除节点 
    		zk.delete("/zk001", -1);
    	}
    

    上述代码中,delete函数需要传入两个参数,第一个参数为需要删除的节点路径。第二个参数为节点版本,如果是-1则代表删除所有版本。

    原创文章,转载请注明出处!!

  • 相关阅读:
    Vim
    一文搞定Samba云服务器配置(阿里云)CentOS8.3
    第四课 婴儿是如何思考的 思维的发展历程
    C++/VS基础篇
    Windows下Qt VS 打包程序 到他人电脑安装运行出现的问题
    第三课 斯金纳
    第二课基础 弗洛伊德
    C++中头文件和实现文件的关系
    字符串 数字 转换
    Ucore lab1实验报告
  • 原文地址:https://www.cnblogs.com/dreamboy/p/9289883.html
Copyright © 2011-2022 走看看