今年年初的时候,写了一篇ZooKeeper的入门文章《初识ZooKeeper》,一直到这一周,才有时间将ZooKeeper整个源码通读了一遍。不能说完全理解了ZooKeeper的工作原理与细节,但是之前心中一直关于ZooKeeper的疑问都得到了解释。

现在网上关于ZooKeeper的文章很多,有介绍Leader选举算法的,有介绍ZooKeeper Server内部原理的,还有介绍ZooKeeper Client的。本文不打算再写类似的内容,而专注与解答读者对ZooKeeper的相关疑问。

ZOOKEEPER在客户端究竟做了什么事情

使用过ZooKeeper的读者都知道,初始化客户端的代码如下:

1
2
3
System.out.println("Starting ZK:");
zk = new ZooKeeper(address, 3000, this);
System.out.println("Finished starting ZK: " + zk);

完成客户段的初始化之后,就可以对ZooKeeper进行相应的操作了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if (zk != null) {
    try {
        Stat s = zk.exists(root, false);
        if (s == null) {
            zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE,
                    CreateMode.PERSISTENT);
        }
    } catch (KeeperException e) {
        System.out
                .println("Keeper exception when instantiating queue: "
                        + e.toString());
    } catch (InterruptedException e) {
        System.out.println("Interrupted exception");
    }
}

虽然上面的代码看起来简单明了,但是ZooKeeper的客户端在后台默默做了许多事情:

1 与ZooKeeper服务端进行通信,包括:连接,发送消息,接受消息。

2 发送心跳信息,保持与ZooKeeper服务端的有效连接与Session的有效性。

3 错误处理,如果客户端当前连接的ZooKeeper服务端失效,自动切换到另一台有效的ZooKeeper服务端。

4 管理Watcher,处理异常调用和Watcher。

WATCHER的事件通知机制是如何实现的

看过Google的分布式锁机制Chubby论文会发现,ZooKeeper中多了一个事件订阅机制:Watcher。那么Watcher内部究竟是如何实现的呢?

其实,在ZooKeeper客户端中,有一个成员变量(ZKWatchManager)专门负责管理所有的Watcher,当用户使用如下代码时:

1
List<String> list = zk.getChildren(path, watcher);

ZooKeeper会将这个Watcher存储在ZKWatchManager中,同时通知ZooKeeper服务器记录该Client对应的Session中的Path下注册的事件类型。当ZooKeeper服务器发生了指定的事件后,ZooKeeper服务器将通知ZooKeeper客户端,ZooKeeper客户端再从ZKWatchManager中找到对应的回调函数,并予以执行。

整个过程中,客户端存储事件的信息和Watcher的执行逻辑,服务端只存储事件的信息。

如何用好ZOOKEEPER客户端

每实例化一个ZooKeeper客户端,就开启了一个Session。ZooKeeper客户端是线程安全的,也可以认为它实现了连接池。

因此,每一个应用只需要实例化一个ZooKeeper客户端即可,同一个ZooKeeper客户端实例可以在不同的线程中使用。

除非你想同一个应用中开启多个Session,使用不同的Watcher,在这种情况下,才需要实例化多个ZooKeeper客户端。

ZOOKEEPER是否对ZNODE有大小限制

如果你仔细看过ZooKeeper的文档,会发现文档中对ZNode的大小做了限制,最大不能超过1M。

这个1M的大小限制在ZooKeeper的客户端和服务端都有限制:

客户端:

1
2
3
4
5
6
packetLen = Integer.getInteger("jute.maxbuffer", 4096 * 1024);
 
int len = incomingBuffer.getInt();
if (len < 0 || len >= packetLen) {
    throw new IOException("Packet len" + len + " is out of range!");
}

服务端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static public final int maxBuffer = determineMaxBuffer();
private static int determineMaxBuffer() {
    String maxBufferString = System.getProperty("jute.maxbuffer");
    try {
        return Integer.parseInt(maxBufferString);
    } catch(Exception e) {
        return 0xfffff;
    }
     
}
 
if (len < 0 || len > maxBuffer) {
    throw new IOException("Unreasonable length = " + len);
}

可以看出,ZooKeeper确实对数据的大小有限制,默认就是1M,如果希望传输超过1M的数据,可以修改环境变量“jute.maxbuffer”即可。

为什么要限制ZOOKEEPER中ZNODE的大小

ZooKeeper是一套高吞吐量的系统,为了提高系统的读取速度,ZooKeeper不允许从文件中读取需要的数据,而是直接从内存中查找。

还句话说,ZooKeeper集群中每一台服务器都包含全量的数据,并且这些数据都会加载到内存中。同时ZNode的数据并支持Append操作,全部都是Replace。

所以从上面分析可以看出,如果ZNode的过大,那么读写某一个ZNode将造成不确定的延时;同时ZNode过大,将过快地耗尽ZooKeeper服务器的内存。这也是为什么ZooKeeper不适合存储大量的数据的原因。

如何提升ZOOKEEPER集群的性能

我们说性能,可以从两个方面去考虑:写入的性能与读取的性能。

由于ZooKeeper的写入首先需要通过Leader,然后这个写入的消息需要传播到半数以上的Fellower通过才能完成整个写入。所以整个集群写入的性能无法通过增加服务器的数量达到目的,相反,整个集群中Fellower数量越多,整个集群写入的性能越差。

ZooKeeper集群中的每一台服务器都可以提供数据的读取服务,所以整个集群中服务器的数量越多,读取的性能就越好。但是Fellower增加又会降低整个集群的写入性能。为了避免这个问题,可以将ZooKeeper集群中部分服务器指定为Observer。

更多关于ZooKeeper的文章请参考:http://www.cnblogs.com/gpcuster/tag/ZooKeeper/

ZOOKEEPER解惑[转]的更多相关文章

  1. ZOOKEEPER解惑

    现在网上关于ZooKeeper的文章很多,有介绍Leader选举算法的,有介绍ZooKeeper Server内部原理的,还有介绍ZooKeeper Client的.本文不打算再写类似的内容,而专注与 ...

  2. 关于zookeeper的自我解惑

    分布式服务框架 Zookeeper -- 管理分布式环境中的数据: http://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/  ...

  3. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

  4. 解惑:在Ubuntu18.04.2的idea上运行Scala支持的spark程序遇到的问题

    解惑:在Ubuntu18.04.2的idea上运行Scala支持的spark程序遇到的问题 一.前言 最近在做一点小的实验,用到了Scala,spark这些东西,于是在Linux平台上来完成,结果一个 ...

  5. Zookeeper 集群的安装及高可用性验证已完成!

    安装包 kafka_2.12-0.10.2.0.tgz zookeeper-3.3.5.tar.gz Java 环境 Zookeeper 和 Kafka 的运行都需要 Java 环境,Kafka 默认 ...

  6. [译]ZOOKEEPER RECIPES-Leader Election

    选主 使用ZooKeeper选主的一个简单方法是,在创建znode时使用Sequence和Ephemeral标志.主要思想是,使用一个znode,比如"/election",每个客 ...

  7. zookeeper源码分析之六session机制

    zookeeper中session意味着一个物理连接,客户端连接服务器成功之后,会发送一个连接型请求,此时就会有session 产生. session由sessionTracker产生的,sessio ...

  8. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  9. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

随机推荐

  1. Redis学习之路(004)- 报错及问题

    在i配置编译的过程中,遇到一下问题: 1. /redis_test: error while loading shared libraries: libhiredis.so.0.13: cannot ...

  2. fedora装机运行第一脚本

    博主原创: #!/bin/bash echo "更换源&更新源......" yum install wget -y yum install yum-fastestmirr ...

  3. Tensorflow 相关概念

    一.概述 人工智能:artificial intelligence 权重: weights 偏差:biases 图中包含输入( input).塑形( reshape). Relu 层( Relulay ...

  4. 【Android】Android解析短信操作

    目录结构: contents structure [-] 获取短信 发送短信 1.获取短信 在AndroidManifest.xml中,添加权限: <uses-permission androi ...

  5. SQL表之间复制数据、选出随机几条数据、删除重复数据、取得自增长列等操作

    --表之间数据复制 SELECT* INTO yozhu FROM yo --复制一份表 SELECT* INTO yozhu1 FROM yo where 1<>1 --只复制表结构,无 ...

  6. MySQL -- 全文检索(自然语言全文检索)

    自然语言全文本检索缺省或者modifier被设置为in natural language mode,都是进行自然语言检索.对于表中的每一行,match()都会返回一个关联值. mysql> CR ...

  7. openkm安装过程

    # java -jar /software/OKMInstaller.jar Running in Linux: 0.9.1-CE (build: 445bef5) Linux distro: rhe ...

  8. Redis命令汇总

    设置服务后台启动 cd /usr/local/redisview redis.conf 将daemonize no改为 daemonize yes保存退出 启动:./reids-server redi ...

  9. iphone5刷机教程

    如果不想麻烦可以在越狱之后添加源,cydia.china3gpp.com打ios7的补丁就可以了 机器为iphone5 美国sprint有锁版 1. 首先备份需要的程序和数据(把各种缓存的影片删掉再备 ...

  10. shell编程入门(一)

    运行Linux程序有三种方法: (1).使文件具有可执行权限,直接运行文件. (2).直接调用命令解释器执行程序(Linux shell是一种解释型语言). (3).使用source执行文件 第一种: ...