1. 概述

Zookeeper是Hadoop的一个子项目,它是分布式系统中的协调系统,可提供的服务主要有:配置服务、名字服务、分布式同步、组服务等。

它有如下的一些特点:

  • 简单

Zookeeper的核心是一个精简的文件系统,它支持一些简单的操作和一些抽象操作,例如,排序和通知。

  • 丰富

Zookeeper的原语操作是很丰富的,可实现一些协调数据结构和协议。例如,分布式队列、分布式锁和一组同级别节点中的“领导者选举”。

  • 高可靠

Zookeeper支持集群模式,可以很容易的解决单点故障问题。

  • 松耦合交互

不同进程间的交互不需要了解彼此,甚至可以不必同时存在,某进程在zookeeper中留下消息后,该进程结束后其它进程还可以读这条消息。

  • 资源库

Zookeeper实现了一个关于通用协调模式的开源共享存储库,能使开发者免于编写这类通用协议。

2. ZooKeeper的安装

  • 独立模式安装

Zookeeper的运行环境是需要java的,建议安装oracle的java6.

可去官网下载一个稳定的版本,然后进行安装: http://zookeeper.apache.org/

解压后在zookeeper的conf目录下创建配置文件zoo.cfg,里面的配置信息可参考统计目录下的zoo_sample.cfg文件,我们这里配置为:

  1. tickTime=2000
  2. initLimit=10
  3. syncLimit=5
  4. dataDir=/opt/zookeeper-data/
  5. clientPort=2181

tickTime : 指定了ZooKeeper的基本时间单位(以毫秒为单位);

initLimit : 指定了启动zookeeper时,zookeeper实例中的随从实例同步到领导实例的初始化连接时间限制,超出时间限制则连接失败(以tickTime为时间单位);

syncLimit : 指定了zookeeper正常运行时,主从节点之间同步数据的时间限制,若超过这个时间限制,那么随从实例将会被丢弃;

dataDir : zookeeper存放数据的目录;

clientPort : 用于连接客户端的端口。

  • 启动一个本地的ZooKeeper 实例
  1. % zkServer.sh start

检查ZooKeeper是否正在运行

  1. echo ruok | nc localhost 2181

若是正常运行的话会打印“imok”。

3. ZooKeeper监控

  • 远程JMX 配置

默认情况下,zookeeper是支持本地的jmx监控的。若需要远程监控zookeeper,则需要进行进行如下配置。

默认的配置有这么一行:

  1. ZOOMAIN="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=$JMXLOCALONLY org.apache.zookeeper.server.quorum.QuorumPeerMain"

咱们在$JMXLOCALONLY后边添加jmx的相关参数配置:

  1. ZOOMAIN="-Dcom.sun.management.jmxremote
  2. -Dcom.sun.management.jmxremote.local.only=$JMXLOCALONLY
  3. -Djava.rmi.server.hostname=192.168.1.8
  4. -Dcom.sun.management.jmxremote.port=1911
  5. -Dcom.sun.management.jmxremote.ssl=false
  6. -Dcom.sun.management.jmxremote.authenticate=false
  7. org.apache.zookeeper.server.quorum.QuorumPeerMain"

这样就可以远程监控了,可以用jconsole.exe或jvisualvm.exe等工具对其进行监控。

  • 身份验证

这里没有配置验证信息,如果需要请参见我的博文 jvisualvm 远程监控tomcat :http://www.cnblogs.com/leocook/p/jvisualvmandtomcat.html

4. Zookeeper的存储模型

Zookeeper的数据存储采用的是结构化存储,结构化存储是没有文件和目录的概念,里边的目录和文件被抽象成了节点(node),zookeeper里可以称为znode。Znode的层次结构如下图:

最上边的是根目录,下边分别是不同级别的子目录。

5. Zookeeper客户端的使用

  • zkCli.sh

可使用./zkCli.sh -server localhost来连接到Zookeeper服务上。

使用ls /可查看根节点下有哪些子节点,可以双击Tab键查看更多命令。

  • Java 客户端

可创建org.apache.zookeeper.ZooKeeper对象来作为zk的客户端,注意,java api里创建zk客户端是异步的,为防止在客户端还未完成创建就被使用的情况,这里可以使用同步计时器,确保zk对象创建完成再被使用。

  • C 客户端

可以使用zhandle_t指针来表示zk客户端,可用zookeeper_init方法来创建。可在ZK_HOME\src\c\src\ cli.c查看部分示例代码。

6. Zookeeper创建Znode

Znode有两种类型:短暂的和持久的。短暂的znode在创建的客户端与服务器端断开(无论是明确的断开还是故障断开)连接时,该znode都会被删除;相反,持久的znode则不会。

  1. public class CreateGroup implements Watcher{
  2. private static final int SESSION_TIMEOUT = 1000;//会话延时
  3.  
  4. private ZooKeeper zk = null;
  5. private CountDownLatch countDownLatch = new CountDownLatch(1);//同步计数器
  6.  
  7. public void process(WatchedEvent event) {
  8. if(event.getState() == KeeperState.SyncConnected){
  9. countDownLatch.countDown();//计数器减一
  10. }
  11. }
  12.  
  13. /**
  14. * 创建zk对象
  15. * 当客户端连接上zookeeper时会执行process(event)里的countDownLatch.countDown(),计数器的值变为0,则countDownLatch.await()方法返回。
  16. * @param hosts
  17. * @throws IOException
  18. * @throws InterruptedException
  19. */
  20. public void connect(String hosts) throws IOException, InterruptedException {
  21. zk = new ZooKeeper(hosts, SESSION_TIMEOUT, this);
  22. countDownLatch.await();//阻塞程序继续执行
  23. }
  24.  
  25. /**
  26. * 创建group
  27. *
  28. * @param groupName 组名
  29. * @throws KeeperException
  30. * @throws InterruptedException
  31. */
  32. public void create(String groupName) throws KeeperException, InterruptedException {
  33. String path = "/" + groupName;
  34. String createPath = zk.create(path, null, Ids.OPEN_ACL_UNSAFE/*允许任何客户端对该znode进行读写*/, CreateMode.PERSISTENT/*持久化的znode*/);
  35. System.out.println("Created " + createPath);
  36. }
  37.  
  38. /**
  39. * 关闭zk
  40. * @throws InterruptedException
  41. */
  42. public void close() throws InterruptedException {
  43. if(zk != null){
  44. try {
  45. zk.close();
  46. } catch (InterruptedException e) {
  47. throw e;
  48. }finally{
  49. zk = null;
  50. System.gc();
  51. }
  52. }
  53. }
  54. }

这里我们使用了同步计数器CountDownLatch,在connect方法中创建执行了zk = new ZooKeeper(hosts, SESSION_TIMEOUT, this);之后,下边接着调用了CountDownLatch对象的await方法阻塞,因为这是zk客户端不一定已经完成了与服务端的连接,在客户端连接到服务端时会触发观察者调用process()方法,我们在方法里边判断一下触发事件的类型,完成连接后计数器减一,connect方法中解除阻塞。

还有两个地方需要注意:这里创建的znode的访问权限是open的,且该znode是持久化存储的。

测试类如下:

  1. public class CreateGroupTest {
  2. private static String hosts = "192.168.1.8";
  3. private static String groupName = "zoo";
  4.  
  5. private CreateGroup createGroup = null;
  6.  
  7. /**
  8. * init
  9. * @throws InterruptedException
  10. * @throws KeeperException
  11. * @throws IOException
  12. */
  13. @Before
  14. public void init() throws KeeperException, InterruptedException, IOException {
  15. createGroup = new CreateGroup();
  16. createGroup.connect(hosts);
  17. }
  18.  
  19. @Test
  20. public void testCreateGroup() throws KeeperException, InterruptedException {
  21. createGroup.create(groupName);
  22. }
  23.  
  24. /**
  25. * 销毁资源
  26. */
  27. @After
  28. public void destroy() {
  29. try {
  30. createGroup.close();
  31. createGroup = null;
  32. System.gc();
  33. } catch (InterruptedException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. }

由于zk对象的创建和销毁代码是可以复用的,所以这里我们把它分装成了接口:

  1. /**
  2. * 连接的观察者,封装了zk的创建等
  3. * @author leo
  4. *
  5. */
  6. public class ConnectionWatcher implements Watcher {
  7. private static final int SESSION_TIMEOUT = 5000;
  8.  
  9. protected ZooKeeper zk = null;
  10. private CountDownLatch countDownLatch = new CountDownLatch(1);
  11.  
  12. public void process(WatchedEvent event) {
  13. KeeperState state = event.getState();
  14.  
  15. if(state == KeeperState.SyncConnected){
  16. countDownLatch.countDown();
  17. }
  18. }
  19.  
  20. /**
  21. * 连接资源
  22. * @param hosts
  23. * @throws IOException
  24. * @throws InterruptedException
  25. */
  26. public void connection(String hosts) throws IOException, InterruptedException {
  27. zk = new ZooKeeper(hosts, SESSION_TIMEOUT, this);
  28. countDownLatch.await();
  29. }
  30.  
  31. /**
  32. * 释放资源
  33. * @throws InterruptedException
  34. */
  35. public void close() throws InterruptedException {
  36. if (null != zk) {
  37. try {
  38. zk.close();
  39. } catch (InterruptedException e) {
  40. throw e;
  41. }finally{
  42. zk = null;
  43. System.gc();
  44. }
  45. }
  46. }
  47. }

7. Zookeeper删除Znode

  1. /**
  2. * 删除分组
  3. * @author leo
  4. *
  5. */
  6. public class DeleteGroup extends ConnectionWatcher {
  7. public void delete(String groupName) {
  8. String path = "/" + groupName;
  9.  
  10. try {
  11. List<String> children = zk.getChildren(path, false);
  12.  
  13. for(String child : children){
  14. zk.delete(path + "/" + child, -1);
  15. }
  16. zk.delete(path, -1);//版本号为-1,
  17. } catch (KeeperException e) {
  18. e.printStackTrace();
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. }

zk.delete(path,version)方法的第二个参数是znode版本号,如果提供的版本号和znode版本号一致才会删除这个znode,这样可以检测出对znode的修改冲突。通过将版本号设置为-1,可以绕过这个版本检测机制,无论znode的版本号是什么,都会直接将其删除。

测试类:

  1. public class DeleteGroupTest {
  2. private static final String HOSTS = "192.168.1.137";
  3. private static final String groupName = "zoo";
  4.  
  5. private DeleteGroup deleteGroup = null;
  6.  
  7. @Before
  8. public void init() throws IOException, InterruptedException {
  9. deleteGroup = new DeleteGroup();
  10. deleteGroup.connection(HOSTS);
  11. }
  12.  
  13. @Test
  14. public void testDelete() throws IOException, InterruptedException, KeeperException {
  15. deleteGroup.delete(groupName);
  16. }
  17.  
  18. @After
  19. public void destroy() throws InterruptedException {
  20. if(null != deleteGroup){
  21. try {
  22. deleteGroup.close();
  23. } catch (InterruptedException e) {
  24. throw e;
  25. }finally{
  26. deleteGroup = null;
  27. System.gc();
  28. }
  29. }
  30. }
  31. }

8. Zookeeper的相关操作

ZooKeeper中共有9中操作:

create:创建一个znode

delete:删除一个znode

exists:测试一个znode

getACL,setACL:获取/设置一个znode的ACL(权限控制)

getChildren:获取一个znode的子节点

getData,setData:获取/设置一个znode所保存的数据

sync:将客户端的znode视图与ZooKeeper同步

这里更新数据是必须要提供znode的版本号(也可以使用-1强制更新,这里可以执行前通过exists方法拿到znode的元数据Stat对象,然后从Stat对象中拿到对应的版本号信息),如果版本号不匹配,则更新会失败。因此一个更新失败的客户端可以尝试是否重试或执行其它操作。

9. ZooKeeper的API

ZooKeeper的api支持多种语言,在操作时可以选择使用同步api还是异步api。同步api一般是直接返回结果,异步api一般是通过回调来传送执行结果的,一般方法中有某参数是类AsyncCallback的内部接口,那么该方法应该就是异步调用,回调方法名为processResult。

10. 观察触发器

可以对客户端和服务器端之间的连接设置观察触发器(后边称之为zookeeper的状态观察触发器),也可以对znode设置观察触发器。

  • 状态观察器

zk的整个生命周期如下:

可在创建zk对象时传入一个观察器,在完成CONNECTING状态到CONNECTED状态时,观察器会触发一个事件,该触发的事件类型为NONE,通过event.getState()方法拿到事件状态为SyncConnected。有一点需要注意的就是,在zk调用close方法时不会触发任何事件,因为这类的显示调用是开发者主动执行的,属于可控的,不用使用事件通知来告知程序。这一块在下篇博文还会详细解说。

  • 设置znode 的观察器

可以在读操作exists、getChildren和getData上设置观察,在执行写操作create、delete和setData将会触发观察事件,当然,在执行写的操作时,也可以选择是否触发znode上设置的观察器,具体可查看相关的api。

当观察的znode 被创建、删除或其数据被更新时 ,设置在exists上的观察将会被触发;

当观察的znode 被删除或数据被更新时 ,设置在getData上的观察将会被触发;

当观察的znode 的子节点被创建、删除或znode 自身被删除时 ,设置在getChildren上的观察将会被触发,可通过观察事件的类型来判断被删除的是znode还是它的子节点。

对于 NodeCreated 和 NodeDeleted 根据路径就能发现是哪个znode被写;对于 NodeChildrenChanged 可根据getChildren来获取新的子节点列表。

注意:在收到收到触发事件到执行读操作之间,znode的状态可能会发生状态,这点需要牢记。

ZooKeeper学习总结(1)——ZooKeeper入门介绍的更多相关文章

  1. [转]ZooKeeper学习第一期---Zookeeper简单介绍

    ZooKeeper学习第一期---Zookeeper简单介绍 http://www.cnblogs.com/sunddenly/p/4033574.html 一.分布式协调技术 在给大家介绍ZooKe ...

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

    一.分布式协调技术 在给大家介绍ZooKeeper之前先来给大家介绍一种技术——分布式协调技术.那么什么是分布式协调技术?那么我来告诉大家,其实分布式协调技术主要用来解决分布式环境当中多个进程之间的同 ...

  3. ZooKeeper学习第一期---Zookeeper简单介绍(转)

    转载来源:https://www.cnblogs.com/sunddenly/p/4033574.html 一.分布式协调技术 在给大家介绍ZooKeeper之前先来给大家介绍一种技术--分布式协调技 ...

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

    一.Zookeeper的四字命令 Zookeeper支持某些特定的四字命令字母与其的交互.他们大多数是查询命令,用来获取Zookeeper服务的当前状态及相关信息.用户在客户端可以通过telnet或n ...

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

    一.Zookeeper的搭建方式 Zookeeper安装方式有三种,单机模式和集群模式以及伪集群模式. ■ 单机模式:Zookeeper只运行在一台服务器上,适合测试环境:■ 伪集群模式:就是在一台物 ...

  6. 【转载】ZooKeeper学习第二期--ZooKeeper安装配置

    原文地址(https://www.cnblogs.com/sunddenly/p/4018459.html) 一.Zookeeper的搭建方式 Zookeeper安装方式有三种,单机模式和集群模式以及 ...

  7. 【转】ZooKeeper学习第二期--Zookeeper命令操作

    一.Zookeeper的四字命令 Zookeeper支持某些特定的四字命令字母与其的交互.他们大多数是查询命令,用来获取Zookeeper服务的当前状态及相关信息.用户在客户端可以通过telnet或n ...

  8. ZooKeeper学习第三期---Zookeeper命令操作(转)

    转载来源:https://www.cnblogs.com/sunddenly/p/4031881.html 一.Zookeeper的四字命令 Zookeeper支持某些特定的四字命令字母与其的交互.他 ...

  9. ZooKeeper学习第二期--ZooKeeper安装配置(转)

    转载来源:https://www.cnblogs.com/sunddenly/p/4018459.html 一.Zookeeper的搭建方式 Zookeeper安装方式有三种,单机模式和集群模式以及伪 ...

  10. Hadoop学习(1)-- 入门介绍

    Hadoop是Apache基金会开发的一个分布式系统基础架构,是时下最流行的分布式系统架构之一.用户可以在不了解分布式底层的情况下,在Hadoop上快速进行分布式应用的开发,并利用集群的计算和存储能力 ...

随机推荐

  1. E20170617-hm

    notation   n. 记号,标记法; implicit   adj. 不言明[含蓄]的; 无疑问的,绝对的; 成为一部份的; 内含的; selector   n. 选择者,选择器; promot ...

  2. E20170706-sl

    erode    vt.     侵蚀,腐蚀 vi.     逐渐毁坏; 削弱,损害; thin  adj.     薄的; 瘦的; 细的; 稀少的; laptop  n.     便携式电脑;

  3. androd基础入门---1环境

    1.项目结构特性 2.模拟器设置 3.编译器的下载 直接点击运行即可

  4. datatable 的使用方法

    遍历datatable的方法 +方法一:DataTable dt = dataSet.Tables[0];for(int i = 0 ; i < dt.Rows.Count ; i++){str ...

  5. ACM_汉诺塔问题(递推dp)

    Problem Description: 最近小G迷上了汉诺塔,他发现n个盘子的汉诺塔问题的最少移动次数是2^n-1,即在移动过程中会产生2^n个系列.由于发生错移产生的系列就增加了,这种错误是放错了 ...

  6. mysql触发器的操作

    一.创建触发器 1.创建有一条执行语句的触发器 CREATE TRIGGER trigger_name BEFORE|AFTER trigger_EVENT(INSERT|DELETE|UPDATE) ...

  7. 关于学习C语言

    c语言作为一种计算机的语言,我们学习它,有助于我们更好的了解计算机,与计算机进行交流,因此,c语言的学习对我们尤其重要. 在这个星期里,我们专业的学生在专业老师的带领下进行了c语言程序实践学习.在这之 ...

  8. 新人浅谈__(数据库的设计__数据库模型图,数据库E-R图,三大范式)

    >>>>  为什么需要规范的数据库设计 在实际的项目开发中,如果系统的数据存储量较大,设计的表比较多,表和表之间的关系比较复杂,就需要首先考虑规范的数据库设计,然后进行创建库, ...

  9. oracle 入门笔记--v$sql和v$sqlarea视图(转载)

    转载于作者:dbtan 原文链接:http://www.dbtan.com/2009/12/vsql-and-vsqlarea-view.html v$sql和v$sqlarea视图: 上文提到,v$ ...

  10. Centos7搭建lamp环境

    首先安装apache Centos7默认已经安装httpd服务,只是没有启动. 如果需要重新安装,输入 yum install -y httpd 启动服务: systemctl start httpd ...