Zookeeper学习总结

一.Zookeeper概述和基本概念

1.Zookeeper背景

随着互联网技术的发展,企业对计算机系统的计算,存储能力要求越来越高,各大IT企业都在追求高并发,海量存储的极致,在这样的背景下,单纯依靠少量高性能单机来完成计算机,云计算的任务已经无法满足需求,
企业的IT架构逐渐由集中式往分布式过渡。所谓的分布式是指:把一个计算任务分解成若干个计算单元,并分派到不同的计算机中去执行,最终汇总计算结果的过程。

2.Zookeeper概述

Zookeeper是源代码开放的分布式协调服务,是一个高性能的分布式数据一致性的解决方案,它将那些复杂的,容易出错的分布式一致性服务封装起来。用户可以通过调用Zookeeper提供的接口来解决一些分布式应用中的实际问题。

3.Zookeeper典型应用场景

(1)数据发布/订阅

数据的发布与订阅,顾名思义就是一方把数据发布出来,另一方通过某种手段获取。
通常数据发布与订阅有两种模式:推模式和拉模式,推模式一般是服务器主动往客户端推送信息,拉模式是客户端主动去服务端请求目标数据(通常采用定时轮询的方式)
Zookeeper采用两种方式互相结合:发布者将数据发布到Zookeeper集群节点上,订阅者通过一定的方法告诉Zookeeper服务器,自己对哪个节点的数据感兴趣,那么在服务端数据发生变化时,就会通知客户端去获取这些信息。

(2)负载均衡

首先在服务端启动的时候,把自己在zookeeper服务器上注册成一个临时节点。zookeeper拥有两种形式的节点,一种是临时节点,一种是永久节点。这两种节点后面的博客会有较为详细的介绍。注册成临时节点后,再服务端出问题时,节点会自动的从 
zookeeper上删除,如此zookeeper服务器上的列表就是最新的可用的列表。
客户端在需要访问服务器的时候首先会去Zookeeper获得所有可用的服务端的连接信息。
客户端通过一定的策略(如随机)选择一个与之建立连接。
当客户端发现连接不可用时,会再次从zookeeper上获取可用的服务端连接,并同时删除之前获取的连接列表。

(3)命名服务

提供名称的服务。如一般使用较多的有两种id,一种是数据库自增长id,一种是UUID,两种id都有局限,自增长id仅适合在单表单库中使用,uuid适合在分布式系统中使用但由于id没有规律难以理解。
而ZK提供了一定的接口可以用来获取一个顺序增长的,可以在集群环境下使用的id。

(4)分布式协调,通知,心跳服务

在分布式服务系统中,我们常常需要知道哪个服务是可用的,哪个服务是不可用的,传统的方式是通过ping主机来实现的,ping得200的结果说明说明该服务是OK的。

而在使用 zookeeper时,可以将所有的服务都注册成一个临时节点,我们判断一个服务是否可用,只需要判断这个节点是否在zookeeper集群中存在就可以了,不需要直接去连接和ping服务所在主机,减少系统的复杂度和对服务主机的压力。

(5)Zookeeper优势

●源代码开放

●高性能,易用稳定,该优势已在众多分布式系统中得到验证

●有着广泛的应用,并且与众多大数据相关技术能实现良好的融合开发。

二.Zookeeper安装以及配置

1.Zookeeper下载
下载ZooKeeper,地址:http://mirrors.hust.edu.cn/apache/zookeeper/
注意:注意版本,启动报错可能找不到主类,可以下载源码版

2.Zookeeper安装配置

3.创建data、log文件夹目录

**4.进入conf目录,创建一个zookeeper的配置文件zoo.cfg,可复制conf/zoo_sample.cfg作为配置文件

 2 # tickTime:CS通信心跳数
 3 # Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。tickTime以毫秒为单位。
 4 tickTime=2000
 5 
 6 # The number of ticks that the initial 
 7 # synchronization phase can take
 8 # initLimit:LF初始通信时限
 9 # 集群中的follower服务器(F)与leader服务器(L)之间初始连接时能容忍的最多心跳数(tickTime的数量)。
10 initLimit=5
11 
12 # The number of ticks that can pass between 
13 # sending a request and getting an acknowledgement
14 # syncLimit:LF同步通信时限
15 # 集群中的follower服务器与leader服务器之间请求和应答之间能容忍的最多心跳数(tickTime的数量)。
16 syncLimit=2
17 
18 # the directory where the snapshot is stored.
19 # do not use /tmp for storage, /tmp here is just 
20 # example sakes.
21 # dataDir:数据文件目录
22 # Zookeeper保存数据的目录,默认情况下,Zookeeper将写数据的日志文件也保存在这个目录里。
23 dataDir=/data/soft/zookeeper-3.4.12/data
24 
25 
26 # dataLogDir:日志文件目录
27 # Zookeeper保存日志文件的目录。
28 dataLogDir=/data/soft/zookeeper-3.4.12/logs
29 
30 # the port at which the clients will connect
31 # clientPort:客户端连接端口
32 # 客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。
33 clientPort=2181
34 
35 # the maximum number of client connections.
36 # increase this if you need to handle more clients
37 #maxClientCnxns=60
38 #
39 # Be sure to read the maintenance section of the 
40 # administrator guide before turning on autopurge.
41 #
42 # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
43 #
44 # The number of snapshots to retain in dataDir 保留数量3
45 autopurge.snapRetainCount=3
46 # Purge task interval in hours
47 # Set to "0" to disable auto purge feature 清理时间间隔1小时
48 autopurge.purgeInterval=1
49 
50 
51 # 服务器名称与地址:集群信息(服务器编号,服务器地址,LF通信端口,选举端口)
52 # 这个配置项的书写格式比较特殊,规则如下:
53 
54 # server.N=YYY:A:B  
55 
56 # 其中N表示服务器编号,YYY表示服务器的IP地址,A为LF通信端口,表示该服务器与集群中的leader交换的信息的端口。B为选举端口,表示选举新leader时服务器间相互通信的端口(当leader挂掉时,其余服务器会相互通信,选择出新的leader)。一般来说,集群中每个服务器的A端口都是一样,每个服务器的B端口也是一样。但是当所采用的为伪集群时,IP地址都一样,只能时A端口和B端口不一样。 

1 # The number of milliseconds of each tick
 2 # tickTime:CS通信心跳数
 3 # Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。tickTime以毫秒为单位。
 4 tickTime=2000
 5 
 6 # The number of ticks that the initial 
 7 # synchronization phase can take
 8 # initLimit:LF初始通信时限
 9 # 集群中的follower服务器(F)与leader服务器(L)之间初始连接时能容忍的最多心跳数(tickTime的数量)。
10 initLimit=5
11 
12 # The number of ticks that can pass between 
13 # sending a request and getting an acknowledgement
14 # syncLimit:LF同步通信时限
15 # 集群中的follower服务器与leader服务器之间请求和应答之间能容忍的最多心跳数(tickTime的数量)。
16 syncLimit=2
17 
18 # the directory where the snapshot is stored.
19 # do not use /tmp for storage, /tmp here is just 
20 # example sakes.
21 # dataDir:数据文件目录
22 # Zookeeper保存数据的目录,默认情况下,Zookeeper将写数据的日志文件也保存在这个目录里。
23 dataDir=/data/soft/zookeeper-3.4.12/data
24 
25 
26 # dataLogDir:日志文件目录
27 # Zookeeper保存日志文件的目录。
28 dataLogDir=/data/soft/zookeeper-3.4.12/logs
29 
30 # the port at which the clients will connect
31 # clientPort:客户端连接端口
32 # 客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。
33 clientPort=2181
34 
35 # the maximum number of client connections.
36 # increase this if you need to handle more clients
37 #maxClientCnxns=60
38 #
39 # Be sure to read the maintenance section of the 
40 # administrator guide before turning on autopurge.
41 #
42 # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
43 #
44 # The number of snapshots to retain in dataDir 保留数量3
45 autopurge.snapRetainCount=3
46 # Purge task interval in hours
47 # Set to "0" to disable auto purge feature 清理时间间隔1小时
48 autopurge.purgeInterval=1
49 
50 
51 # 服务器名称与地址:集群信息(服务器编号,服务器地址,LF通信端口,选举端口)
52 # 这个配置项的书写格式比较特殊,规则如下:
53 
54 # server.N=YYY:A:B  
55 
56 # 其中N表示服务器编号,YYY表示服务器的IP地址,A为LF通信端口,表示该服务器与集群中的leader交换的信息的端口。B为选举端口,表示选举新leader时服务器间相互通信的端口(当leader挂掉时,其余服务器会相互通信,选择出新的leader)。一般来说,集群中每个服务器的A端口都是一样,每个服务器的B端口也是一样。但是当所采用的为伪集群时,IP地址都一样,只能时A端口和B端口不一样。 

5.启动Zookeeper


三.Zookeeper基本命令

help 查看所有命令
ls  查看根路径下的节点 ls / 
create  创建普通的永久节点 create /hello "helloword"
create -s 创建带序号的永久节点 create -s /app1 "app1 node"
create -e 创建普通的临时节点 create -e /app2 "app2 node"
create -e -s 创建带序号的临时节点 create -e -s /app3 "app3 node"
get 查找节点数据 get /hello
stat 查看节点状态 stat /hello
set 修改节点数据 set /hello 'hello node'
delete 删除节点 delete /hello(设hello节点下没子节点)
deleteall 递归删除节点 deleteall /hello (设hello节点下有子节点)

四.Zookeeper通过java实现的demo

1.需要引入的pom依赖

 <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.7</version>
        </dependency>

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.0.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.0.1</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.2</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>

2.创建测试类

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.junit.Before;
import org.junit.Test;

public class ZookeeperApiTest {

    private  CuratorFramework client = null;
    /**
     * 创建客户端
     * 1.创建连接失败重试策略对象
     * 2.创建客户端对象
     */
    @Before
    public void before(){

        /**创建重试的连接对象
         *RetryPolicy接口 失败重试策略的公共接口;ExponentialBackoffRetry 实现类 是失败重试celue接口实现类
         * 参数1:两次重试之间等待的初始时间(单位:毫秒)
         * 参数2:最大重试次数
         */
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000,3);
        /**
         * 创建客户端对象
         * 参数1:连接zookeeper服务器IP地址和端口号
         * 参数2:会话超时时间(单位:毫秒)
         * 参数3:连接超时时间(单位:毫秒)
         * 参数4:失败失败重试策略
         */
        client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", 1000, 1000, retryPolicy);
    }

    /**
     * 创建节点
     * 1.开启客户端(会阻塞到会话连接成功为止)
     * 2.创建节点
     * 3.关闭节点
     */
    @Test
    public void createNode() throws Exception {
        //开启客户端
        client.start();
        // 方式一:创建一个空节点(只能创建一个节点)
        //client.create().forPath("/app1");
        //方式二:创建一个有内容的节点(只能创建一层节点)
        //client.create().forPath("/app2","app2 node".getBytes());
        //方式三:创建多层节点
        //client.create().creatingParentsIfNeeded().forPath("/app3/a","a node".getBytes());
        //创建持久性节点(CreateMode.PERSISTENT)
        //client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath("/app3/b","b node".getBytes());
        //创建带序号持久性节点(CreateMode.PERSISTENT)
        //client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath("/app3/c","c node".getBytes());
        //创建临时节点
        //client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath("/app3/d","d node".getBytes());
        // 创建带序号临时节点
        client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/app3/e","e node".getBytes());


        Thread.sleep(10000);
        // 关闭客户端
        client.close();
    }

    /**
     * 修改节点数据
     * 1.开启客户端
     * 2.修改节点
     * 3.关闭客户端
     */
    @Test
    public void updateNode() throws Exception {
        // 1.开启客户端
        client.start();
        //2.修改节点
        client.setData().forPath("/app1","app1 node".getBytes());
        //3.关闭客户端
        client.close();
    }

    /**
     * 获取节点数据
     * 1.开启客户端
     * 2.获取节点数据
     * 3.关闭客户端
     */
    @Test
    public void  findNode() throws Exception {
        // 1.开启客户端
        client.start();
        //2.获取节点数据
        byte[] bytes = client.getData().forPath("/app1");
        System.out.println("节点数据:"+new String(bytes));
        //3.关闭客户端
        client.close();
    }

    /**
     * 删除节点
     * 1.开启客户端
     * 2.删除节点
     * 3.关闭客户端
     */
    @Test
    public void deleteNode() throws Exception {
        // 1.开启客户端
        client.start();
        //方式1:删除一个子节点(此节点下面不能有子节点)
        //client.delete().forPath("/app1");
        //方式2:带有节点并递归删除其子节点
        //client.delete().deletingChildrenIfNeeded().forPath("/app3");
        //方式3:强制保证删除一个节点
        client.delete().guaranteed().forPath("/app2");
        //3.关闭客户端
        client.close();
    }

}
古今成大事者,不唯有超世之才,必有坚韧不拔之志!
原文地址:https://www.cnblogs.com/songwp/p/15014753.html