在之前的章节中,我们使用zkCli工具介绍了ZooKeeper的基本操作。从本章开始,我们将会看到在应用中如何通过API来进行操作。首先介绍一下如何使用ZooKeeper的API进行开发,展示如何创建会话,实现监视点(watcher)。我们还是从主-从模式例子开始进行编码

1.1建立ZooKeeper会话

  ZooKeeper的API围绕ZooKeeper的句柄(handle)来构建,每个API调用都需要传递这个句柄。这个句柄代表与ZooKeeper之间的一个会话。在图3-1中,与ZooKeeper服务器已经建立的一个会话如果断开,这个会话就会迁移到另一台ZooKeeper服务器上。只要会话还存活着,这个句柄就仍然有效,ZooKeeper客户端库会持续保持这个活跃连接,以保证与ZooKeeper服务器之间的会话存活。如果句柄关闭,ZooKeeper客户端库会告知ZooKeeper服务器终止这个会话。如果ZooKeeper发现客户端已经死掉,就会使这个会话无效。如果客户端之后尝试重新连接到ZooKeeper服务器,使用之前无效会话对应的那个句柄进行连接,那么ZooKeeper服务器会通知客户端库,这个会话已失效,使用这个句柄进行的任何操作都会返回错误。

创建ZooKeeper句柄的构造函数如下所示:

ZooKeeper(
String connectString,
int sessionTimeout,
Watcher watcher)

其中:

connectString
  包含主机名和ZooKeeper服务器的端口。我们之前通过zkCli连接
ZooKeeper服务时,已经列出过这些服务器。

sessionTimeout
  以毫秒为单位,表示ZooKeeper等待客户端通信的最长时间,之后会声
明会话已死亡。目前我们使用15000,即15秒。这就是说如果ZooKeeper与
客户端有15秒的时间无法进行通信,ZooKeeper就会终止客户端的会话。需
要注意,这个值比较大,但对于我们后续的实验会非常有用。ZooKeeper会
话一般设置超时时间为5~10秒。
 watcher
  用于接收会话事件的一个对象,这个对象需要我们自己创建。因为
Wacher定义为接口,所以我们需要自己实现一,然后初始化这个类的
实例并传递ZooKeeper的构造函数中。客户端使用Watcher接口来监控与
ZooKeeper之间会话的健康情况。与ZooKeeper服务器之间建立或失去连接
时就会产生事件。它们同样还能用于监控ZooKeeper数据的变化。最终,如
果与ZooKeeper的会话过期,也会通过Watcher接口传递事件来通知客户端
的应用。

1.1.1实现一个Watcher

为了从ZooKeeper接收通知,我们需要实现监视点。首先让我们进一步了解Watcher接口,该接口的定义如下:

public interface Watcher {
void process(WatchedEvent event);
}

这个接口没有多少内容,我们不得不自己实现,但现在我们只是简单
地输出事件。所以,让我们从一个名为Master的类开始实现示例:

import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher;
public class Master implements Watcher {
ZooKeeper zk;
String hostPort;
Master(String hostPort) {
this.hostPort = hostPort; ①
}
void startZK() {
zk = new ZooKeeper(hostPort, 15000, this); ②
}
public void process(WatchedEvent e) {
System.out.println(e); ③
}
public static void main(String args[])
throws Exception {
Master m = new Master(args[0]);
m.startZK();
// wait for a bit
Thread.sleep(60000); ④
}
}

④我们连接到ZooKeeper后,后台就会有一个线程来维护这个
ZooKeeper会话。该线程为守护线程,也就是说线程即使处于活跃状态,
程序也可以退出。因此我们在程序退出前休眠一段时间,以便我们可以看
到事件的发生。

所谓守护线程是指在程序运行的时候在后台提供一种通用服务的线程,比如垃圾回收线程就是一个很称职的守护者,并且这种线程并不属于程序中不可或缺的部分。因 此,当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程。反过来说,只要任何非守护线程还在运行,程序就不会终止。

守护线程和用户线程的没啥本质的区别:唯一的不同之处就在于虚拟机的离开:如果用户线程已经全部退出运行了,只剩下守护线程存在了,虚拟机也就退出了。 因为没有了被守护者,守护线程也就没有工作可做了,也就没有继续运行程序的必要了。

运行:

... - INFO [...] - Client environment:zookeeper.version=3.4.5-1392090, ... ①
...
... - INFO [...] - Initiating client connection,
connectString=127.0.0.1:2181 ... ②
... - INFO [...] - Opening socket connection to server
localhost/127.0.0.1:2181. ...
... - INFO [...] - Socket connection established to localhost/127.0.0.1:2181,
initiating session
... - INFO [...] - Session establishment complete on server
localhost/127.0.0.1:2181, ... ③
WatchedEvent state:SyncConnected type:None path:null ④

  ZooKeeper客户端API产生很多日志消息,使用户可以了解发生了什么。日志非常详细,可以通过配置文件来禁用这么详细的日志,不过在开发时,这些消息非常有用,甚至在正式部署后,发生了某些我们不希望发生的事情,这些日志消息也是非常有价值的。

①前面⼏⾏日志消息描述了ZooKeeper客户端的实现和环境。
②当客户端初始化⼀个到ZooKeeper服务器的连接时,⽆论是最初的
连接还是随后的重连接,都会产⽣这些日志消息。
③这个消息展示了连接建立之后,该连接的信息,其中包括客户端所
连接的主机和端⼝信息,以及这个会话与服务器协商的超时时间。如果服
务器发现请求的会话超时时间太短或太长,服务器会调整会话超时时间。
④最后这⾏并不是ZooKeeper库所输出,⽽是我们实现的
Watcher.process(WatchedEvent e)函数中输出的WatchEvent对象。

1.1.2运行Watcher的示例

  如果我们不启动ZooKeeper服务就启动主节点,这样会发生什么呢?我们可以试一下。停止服务,然后运行Master,看到了什么?在之前输出中的最后一句,即WatchedEvent的数据,现在并没有出现。因为ZooKeeper库无法连接ZooKeeper服务器,所以我们看不到这些信息了。

    现在我们启动服务器,然后运行Master,之后停止服务器并保持Master继续运行。你会看到在SyncConnected事件之后发生了Disconnected事件。

  当开发者看到Disconnected事件时,有些人认为需要创建一个新的ZooKeeper句柄来重新连接服务。不要这么做!当你启动服务器,然后启动Master,再重启服务器时看一下发生了什么。你看到SyncConnected事件之后为Disconnected事件,然后又是一个SyncConnected事件。ZooKeeper客户端库负责为你重新连接服务。当不幸遇到网络中断或服务器故障时,ZooKeeper可以处理这些故障问题。

  我们需要知道ZooKeeper本身也可能发生这些故障问题。一个ZooKeeper服务器也许会故障或失去网络连接,类似我们停止主节点后所模拟的场景。如果ZooKeeper服务至少由三台服务器组成,那么一个服务器的故障并不会导致服务中断。而客户端也会很快收到Disconnected事件,之后便为SyncConnected事件。

注意:ZooKeeper管理连接

请不要自己试着去管理ZooKeeper客户端连接。ZooKeeper客户端库会
监控与服务之间的连接,客户端库不仅告诉我们连接发生问题,还会主动
尝试重新建立通信。一般客户端开发库会很快重建会话,以便最小化应用
的影响。所以不要关闭会话后再启动一个新的会话,这样会增加系统负
载,并导致更长时间的中断。

  

  客户端就像除了休眠外什么都没做一样,而我们通过发生的事件可以看到后台到底发生了什么。我们还可以看看ZooKeeper服务端都发生了什么。ZooKeeper有两种管理接口:JMX和四字母组成的命令。第10章会深入讨论这些接口,现在我们通过stat和dump这两个四字母命令来看看服务器上发生了什么。要使用这些命令,需要先通过telnet连接到客户端端口2181,然后输入这些命令(在命令后输入Enter键)。例如,如果启动Master这个程序后,使用stat命令,我们会看到以下输出信息:

$ telnet 127.0.0.1 2181
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
stat
ZooKeeper version: 3.4.5-1392090, built on 09/30/2012 17:52 GMT
Clients:
/127.0.0.1:39470[1](queued=0,recved=3,sent=3)
/127.0.0.1:39471[0](queued=0,recved=1,sent=0)
Latency min/avg/max: 0/5/48
Received: 34
Sent: 33
Connections: 2
Outstanding: 0
Zxid: 0x17
Mode: standalone
Node count: 4
Connection closed by foreign host.

我们从输出信息看到有两个客户端连接到ZooKeeper服务器。一个是Master程序,另一个为Telnet连接。如果我们启动Master程序后,使⽤dump命令,我们会看到以下输出信息:

$ telnet 127.0.0.1 2181
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
dump
SessionTracker dump:
Session Sets (3):
0 expire at Wed Nov 28 20:34:00 PST 2012:
0 expire at Wed Nov 28 20:34:02 PST 2012:
1 expire at Wed Nov 28 20:34:04 PST 2012:
0x13b4a4d22070006
ephemeral nodes dump:
Sessions with Ephemerals (0):
Connection closed by foreign host.

  我们从输出信息中看到有⼀个活动的会话,这个会话属于Master程序。我们还能看到这个会话还有多长时间会过期。会话超时的过期时间取决于我们创建ZooKeeper对象时所指定的值。让我结束Master程序,再次使用dump命令来看⼀下活动的会话信息。你会注意到会话过一段时间后才消失。这是因为直到会话超时时间过了以后,服务器才会结束这个会话。当然,客户端会不断延续与ZooKeeper服务器的活动连接的到期时间。当Master结束时,最好的方式是使会话立即消失。这可以通过ZooKeeper.close()方法来结束。一旦调用close方法后,ZooKeeper对象实例所表示的会话就会被销毁。让我们在示例程序中加入close调用:

void stopZK() throws Exception { zk.close(); }
public static void main(String args[]) throws Exception {
Master m = new Master(args[0]);
m.startZK();
// wait for a bit
Thread.sleep(60000);
m.stopZK();
}

现在我们可以再次运行Master程序,运行dump命令来看一下会话是否
还存活。因为Master程序中显示关闭了会话,所以ZooKeeper关闭会话前就
不需要等待会话超时了。

开始使⽤ZooKeeper的API的更多相关文章

  1. Zookeeper C API 指南四(C API 概览)(转)

    上一节<Zookeeper C API 指南三(回调函数)>重点讲了 Zookeeper C API 中各种回调函数的原型,本节将切入正题,正式讲解 Zookeeper C API.相信大 ...

  2. 9. 使用ZooKeeper Java API编程

    ZooKeeper是用Java开发的,3.4.6版本的Java API文档可以在http://zookeeper.apache.org/doc/r3.4.6/api/index.html上找到. Ti ...

  3. (原) 2.1 Zookeeper原生API使用

    本文为原创文章,转载请注明出处,谢谢 Zookeeper原生API使用 1.jar包引入,演示版本为3.4.6,非maven项目,可以下载jar包导入到项目中 <dependency> & ...

  4. Zookeeper C API 指南三(回调函数)(转)

    2013-02-21 12:54 by Haippy, 9237 阅读, 0 评论, 收藏, 编辑 接上一篇<Zookeeper C API 指南二(监视(Wathes), 基本常量和结构体介绍 ...

  5. Zookeeper C API 指南一(转)

    Zookeeper 监视(Watches) 简介 Zookeeper C API 的声明和描述在 include/zookeeper.h 中可以找到,另外大部分的 Zookeeper C API 常量 ...

  6. zookeeper client API实现(python kazoo 的实现)

    这里主要分析zookeeper client API的实现方式,以python kazoo的实现代码为蓝本进行逻辑分析. 一.代码框架及介绍 API分为同步模式和异步模式.同步模式是在异步模式的基础上 ...

  7. Zookeeper系列三:Zookeeper客户端的使用(Zookeeper原生API如何进行调用、ZKClient、Curator)和Zookeeper会话

    一.Zookeeper原生API如何进行调用 准备工作: 首先在新建一个maven项目ZK-Demo,然后在pom.xml里面引入zk的依赖 <dependency> <groupI ...

  8. Hadoop生态圈-zookeeper的API用法详解

    Hadoop生态圈-zookeeper的API用法详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.测试前准备 1>.开启集群 [yinzhengjie@s101 ~] ...

  9. zookeeper原生API做java客户端

    简介 本文是使用apache提供的原生api做zookeeper客户端 jar包 zookeeper-3.4.5.jar   Demo package bjsxt.zookeeper.base; im ...

随机推荐

  1. DevOps实践

    云计算 [ 01 ]GitLab+Rancher实践DevOps[转载] [ 02 ]Kubernetes CentOS 7.4搭建Kubernetes 1.8.5集群 kubeadm搭建kubern ...

  2. ptr_fun

    ptr_fun 分类: C/C++2012-05-05 20:21 593人阅读 评论(0) 收藏 举报 functionclassfunobjectreturningtypes   目录(?)[-] ...

  3. C++题目(论述类)

    0.面向对象 三大特性:封装性.继承性.多态性 1.static  ①只进行一次初始化,而且保存在静态存储区,是在程序运行时就进行初始化了: ②当我们同时编译多个源文件(.c文件)时,所有未加stat ...

  4. 让svn具有分布式的功能。

    最近开发遇到了个难事.公司的svn库不能随便提交,必须要经过验证.但是平时修改太多,如果不提交到svn说不定前面被删掉的代码后面又需要了.svn自带的relocate和switch都不能达到要求.找遍 ...

  5. java分布式(一)

    分布式架构的演进 初始阶段架构 应用服务和数据服务分离阶段 使用缓存改善性能 使用应用服务器集群 数据库读写分离 反向代理和CDN加速 分布式文件系统和分布式数据库 使用NoSql和搜索引擎 业务拆分 ...

  6. CF1114F Please, another Queries on Array?

    CF1114F Please, another Queries on Array? 考虑用线段树维护取模后的区间积和真正的区间积所含有的质因子. 每次询问查得这两个值后,一乘一除,即可算出该区间积的欧 ...

  7. BZOJ4518 Sdoi2016 征途 【斜率优化DP】 *

    BZOJ4518 Sdoi2016 征途 Description Pine开始了从S地到T地的征途. 从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站. Pine计划用m天到达T地.除第m ...

  8. ASP.NET性能优化原则

    从哪些方面对asp.net进行性能优化,本文作了详细的阐述,希望对大家有所帮助. 一.SqlDataRead和Dataset的选择Sqldataread优点:读取数据非常快.如果对返回的数据不需做大量 ...

  9. java 乐观锁CAS

    乐观锁是一种思想,本身代码里并没有lock或synchronized关键字进行修饰.而是采用一种version. 即先从数据库中查询一条记录得到version值,在更新这条记录时在where条件中对这 ...

  10. Cockpit 服务化管理工具

    Cockpit 是红帽开发的网页版图像化服务管理工具,优点是无需中间层,且可以管理多种服务. 根据其项目主站描述,Cockpit 有如下特点: 从易用性考虑设计,方便管理人员使用,而不是仅仅的终端命令 ...