ZooKeeper快速入门
1 ZooKeeper概述
ZooKeeper是一个分布式协调服务,用于管理大量主机。 协调和管理分布式环境中的服务是一个复杂的过程。 ZooKeeper以其简单的架构和API解决了这个问题。 ZooKeeper允许开发人员专注于核心应用程序逻辑,而不必担心应用程序的分布式特性。
ZooKeeper框架最初是在“Yahoo!”中构建的,用于以简单和强大的方式访问他们的应用程序。 后来,Apache ZooKeeper成为了Hadoop、HBase和其他分布式框架所使用的有组织服务的标准。 例如,Apache HBase使用ZooKeeper来跟踪分布式数据的状态。
在讲述之前,我们知道关于分布式应用程序的一点事情是非常重要的。 因此,让我们以分布式应用程序的快速概述开始讨论。
1、分布式应用程序(Distributed Application)
分布式应用程序可以在给定时间(同时)在网络中的多个系统上运行,通过协调它们以快速有效的方式完成特定任务。通常,通过使用所有涉及系统的计算能力,分布式应用程序可以在几分钟内完成由非分布式应用程序(在单个系统中运行)需要数小时完成的复杂和耗时的任务。
通过将分布式应用程序配置为在更多系统上运行,可以进一步缩短完成任务的时间。运行分布式应用程序的一组系统称为集群,集群中运行的每台计算机称为节点。
分布式应用程序有两部分,服务器和客户端应用程序。服务器应用程序实际上是分布式的,并且具有通用接口,以便客户端可以连接到群集中的任何服务器并获得相同的结果。客户端应用程序是与分布式应用程序进行交互的工具。
分布式应用程序的优点:
可靠性 - 单个或少数系统的故障不会导致整个系统失效。
可扩展性 - 通过添加更多的机器,可以在需要时提高性能,而对应用程序的配置进行微小更改而无需停机。
透明度 - 隐藏系统的复杂性并将其自身显示为单个实体/应用程序。
分布式应用程序的挑战:
竞争条件 - 两台或两台以上试图执行特定任务的机器,实际上任何时候都只能由一台机器完成。 例如,共享资源只能在任何给定时间由单台机器进行修改。
死锁 - 两个或多个等待对方无限期完成的操作。
不一致 - 数据部分失败。
2、Apache ZooKeeper意味着什么
Apache ZooKeeper是由群集(节点组)使用的一种服务,用于彼此协调并通过强大的同步技术维护共享数据。 ZooKeeper本身就是一个分布式应用程序,提供编写分布式应用程序的服务。
ZooKeeper提供的常用服务如下:
·命名服务 - 按名称识别群集中的节点。 它与DNS类似,但是用于节点。
·配置管理 - 加入节点的系统的最新和最新配置信息。
·群集管理 - 实时连接/离开群集中的节点和节点状态。
·领导选举 - 选择一个节点作为协调目标的领导者。
·锁定和同步服务 - 在修改数据时锁定数据。 此机制可帮助您在连接其他分布式应用程序(如Apache HBase)时进行自动故障恢复。
·高度可靠的数据注册表 - 数据即使在一个或几个节点停机时也可用。
分布式应用程序提供了很多好处,但它们也会带来一些复杂而难以解决的挑战。 ZooKeeper框架提供了一个完整的机制来克服所有的挑战。 使用故障安全同步方法处理竞态条件和死锁。 另一个主要缺点是数据不一致,这是ZooKeeper用原子性来解决的。
3、ZooKeeper的优点:
以下是使用ZooKeeper的好处:
·简单的分布式协调过程
·同步 - 服务器进程之间的相互排斥和协作。 此过程有助于Apache HBase进行配置管理。
·有序消息
·序列化 - 根据特定规则对数据进行编码。 确保您的应用程序运行一致 这种方法可以用在MapReduce中来协调队列以执行正在运行的线程。
·可靠性
·原子性 - 数据传输要么成功,要么完全失败,但没有事务是局部的。
2 ZooKeeper原理
在深入ZooKeeper的工作之前,让我们看看ZooKeeper的基本概念。 我们将在本章中讨论以下主题:
Architecture (架构)
Hierarchical namespace(分层命名空间)
Session(会话)
Watches(监听)
1、ZooKeeper的架构
看看下面的图表。 它描述了ZooKeeper的“client - server架构”。
下表中解释了ZooKeeper体系结构中的每个组件。
角色 |
描述 |
Client |
客户端是分布式应用程序集群中的一个节点,可以从服务器访问信息。 在特定的时间间隔内,每个客户端都会向服务器发送一条消息,让服务器知道客户端仍在运行。 同样,服务器在客户端连接时发送确认。 如果连接的服务器没有响应,客户端会自动将消息重定向到另一台服务器。 |
Server |
服务器是我们ZooKeeper集合中的一个节点,它为客户提供所有服务。 向客户发出通知,告知服务器处于活动状态。 |
Ensemble |
ZooKeeper服务器组。 组成一个集合所需的最小节点数是3。 |
Leader |
如果任何连接节点失败,则执行自动恢复的服务器节点。 *是在服务启动时选出的。 |
Follower |
遵循领导指令的服务器节点。 |
2、分层命名空间
下图描述了用于内存表示的ZooKeeper文件系统的树结构。 ZooKeeper节点被称为znode。 每个znode都由一个名称标识,并由一系列路径(/)分隔开。
·在图中,首先您有一个由“/”分隔的根znode。 在根目录下,您有两个逻辑名称空间配置和工作。
·配置名称空间用于集中配置管理,而工作者名称空间用于命名。
·在config命名空间下,每个znode最多可以存储1MB的数据。 这与UNIX文件系统类似,除了父节点也可以存储数据。 这种结构的主要目的是存储同步数据并描述znode的元数据。 这个结构被称为ZooKeeper数据模型。
ZooKeeper数据模型中的每个znode都维护一个stat结构。 统计信息只是提供znode的元数据。 它由版本号(Version number),动作控制列表(Action control list,即ACL),时间戳(Timestamp)和数据长度(Data length)组成。
·版本号:每个znode都有一个版本号,这意味着每当与znode相关的数据发生变化时,其对应的版本号也会增加。 当多个zookeeper客户端试图通过同一个znode执行操作时,使用版本号很重要。
·动作控制列表(ACL):ACL基本上是用于访问znode的认证机制。 它管理所有的znode读写操作。
·时间戳:时间戳表示从znode创建和修改过去的时间。 它通常以毫秒表示。 ZooKeeper从“事务ID”(zxid)中识别对znodes的每个更改。 Zxid是唯一的,并为每个事务维护时间,以便您可以轻松识别从一个请求到另一个请求所用的时间。
·数据长度:存储在znode中的数据总量是数据长度。 您最多可以存储1MB的数据。
Znode的类型
Znodes被分类为持久性(persistence),连续性(sequential)和短暂性(ephemeral)。
·持久znode:即使在创建特定znode的客户端断开连接之后,持久znode仍处于活动状态。默认情况下,除非另有说明,否则所有znode都是永久的。
·短暂的znode:临时的znode在客户活着之前一直处于活动状态。当客户端从ZooKeeper集成中断开连接时,会自动删除临时znode。出于这个原因,只有短暂的znode不允许有更多的孩子。如果一个短暂的znode被删除,那么下一个合适的节点将填充它的位置。短暂节点在*选举中发挥重要作用。
·顺序znode:顺序znode可以是持久性或短暂性的。当一个新的znode被创建为一个连续的znode时,ZooKeeper通过将一个10位数的***附加到原始名称来设置znode的路径。例如,如果将具有path / myapp的znode创建为顺序znode,则ZooKeeper会将路径更改为/ myapp0000000001,并将下一个***设置为0000000002.如果两个顺序znode同时创建,则ZooKeeper将永远不会使用相同的编号每个znode。顺序节点在锁定和同步中起着重要作用。
3、会话
会话对于ZooKeeper的操作非常重要。 会话中的请求按先进先出顺序执行。 一旦客户端连接到服务器,会话将被建立并且会话ID被分配给客户端。
客户端以特定的时间间隔发送检测信号以保持会话有效。 如果ZooKeeper集合在服务启动时指定的时间段(会话超时)之外没有收到来自客户端的心跳,它会判定客户端已死亡。
会话超时通常以毫秒表示。 当会话因任何原因结束时,会话期间创建的临时znode也会被删除。
4、监控(Watches)
Watches是客户端获取有关ZooKeeper集成中更改的通知的简单机制。 客户可以在阅读特定znode时设置手表。Watches向已注册的客户端发送任何znode(在其上的客户端寄存器)更改的通知。
Znode变化是修改与znode相关的数据或znode的子节点中的变化。Watches只触发一次。 如果客户想要再次发出通知,则必须通过另一次读取操作完成。 当连接会话过期时,客户端将与服务器断开连接,并且关联的Watches也会被移除。
3 ZooKeeper工作流程
一旦ZooKeeper启动,它将等待客户端连接。 客户端将连接到ZooKeeper集合中的一个节点。 它可能是一个领导者或一个追随者节点。 一旦连接了一个客户端,该节点就为特定客户端分配一个会话ID并向客户端发送一个确认。 如果客户端没有得到确认,它只会尝试连接ZooKeeper集合中的另一个节点。 一旦连接到节点,客户端将定期向节点发送心跳信号,以确保连接不会丢失。
·如果客户端想要读取特定的znode,它会向具有znode路径的节点发送读取请求,并且节点通过从其自己的数据库中获取请求的znode来返回请求的znode。 出于这个原因,ZooKeeper集合中的读取速度很快。
·如果客户端想要将数据存储在ZooKeeper集合中,它会将znode路径和数据发送到服务器。 连接的服务器会将请求转发给领导,然后领导将重新向所有追随者发出请求。 如果只有大多数节点响应成功,则写请求将成功,并且成功的返回码将被发送到客户端。 否则,写入请求将失败。 绝大多数节点称为Quorum。
ZooKeeper服务器组中的结点(Znodes)
让我们分析ZooKeeper集合中节点数量不同的影响。
·如果我们有一个节点,那么当该节点失败时,ZooKeeper集合失败。它有助于“单点故障”,不建议在生产环境中使用。
·如果我们有两个节点,一个节点失败,我们也没有多数,因为两分之一不是多数。
·如果我们有三个节点,一个节点失败,我们拥有多数,所以这是最低要求。 ZooKeeper合奏必须在现场制作环境中至少有三个节点。
·如果我们有四个节点并且两个节点失败,它将再次失败,并且与具有三个节点类似。额外节点不起任何作用,因此,最好以奇数添加节点,例如3,5,7。
我们知道写入过程比ZooKeeper集成中的读取过程要贵,因为所有节点都需要在其数据库中写入相同的数据。因此,与具有大量节点的平衡环境相比,节点数量少(3,5或7)会更好。
下图描述了ZooKeeper WorkFlow,后面的表格解释了它的不同组件。
组件 |
描述 |
Write |
写入过程由领导节点处理。 领导者将写入请求转发给所有的znode,并等待znode的答案。 如果有一半的znodes回复,则写入过程完成。 |
Read |
读取由特定连接的znode内部执行,因此不需要与群集交互。 |
Replicated Database |
它用于在zookeeper中存储数据。 每个znode都有自己的数据库,每个znode在每次一致性的帮助下都有相同的数据。 |
Leader |
Leader是负责处理写入请求的Znode。 |
Follower |
追随者收到来自客户端的写入请求并将其转发给领导者znode。 |
Request Processor |
仅出现在领导者节点中。 它支配来自跟随者节点的写入请求。 |
Atomic broadcasts |
负责将领导者节点的变化传播给追随者节点。 |
4 ZooKeeper选举Leader
让我们分析一下如何在ZooKeeper集合中选出一个领导者节点。考虑一个集群中有N个节点。领导选举的过程如下:
1.所有节点使用相同的路径/ app / leader_election / guid_创建顺序的短暂znode。
2. ZooKeeper集合会将10位***添加到路径中,并且创建的znode将为/ app / leader_election / guid_0000000001,/ app / leader_election / guid_0000000002等。
3.对于给定的实例,在znode中创建最小数字的节点成为领导者,所有其他节点都是追随者。
4.每个跟随者节点观察具有次最小号码的znode。例如,创建znode / app / leader_election / guid_0000000008的节点将观看znode / app / leader_election / guid_0000000007,创建znode / app / leader_election / guid_0000000007的节点将观看znode / app / leader_election / guid_0000000006。
5.如果领导者失败,则其相应的znode / app / leader_electionN被删除。
6.下一个在线追随者节点将通过观察者获得关于领队移除的通知。
7.下一个在线追随者节点将检查是否有其他节点号码最小。如果没有,那么它将承担领导者的角色。否则,它会找到创建最小编号的znode作为组长的节点。
8.类似地,所有其他跟随者节点选择创建具有最小数量的znode作为领导者的节点。
从头开始,*选是一个复杂的过程。 但ZooKeeper服务使其非常简单。 下一章将介绍ZooKeeper的开发目的。
5 ZooKeeper安装
在安装ZooKeeper之前,请确保您的系统正在以下任一操作系统上运行:
·任何Linux操作系统 - 支持开发和部署。 演示应用程序是首选。
·Windows操作系统 - 仅支持开发。
·Mac OS - 仅支持开发。
ZooKeeper服务器是用Java创建的,它运行在JVM上。 您需要使用JDK 6或更高版本。
现在,按照下面的步骤在您的机器上安装ZooKeeper框架。
第1步:验证Java安装
我们相信您的系统上已经安装了Java环境。 只需使用以下命令验证它。
$ java -version |
如果您的计算机上安装了Java,则可以看到已安装的Java版本。 否则,请按照下面的简单步骤安装最新版本的Java。
步骤1.1:下载JDK
通过访问以下链接并下载最新版本来下载最新版本的JDK。
http://www.oracle.com/technetwork/java/javase/downloads/index.html
最新版本(在写本教程时)是JDK 8u 60,文件是“jdk-8u60-linux-x64.tar.gz”。 请在您的机器上下载该文件。
步骤1.2:解压文件
通常,文件被下载到下载文件夹。 验证它并使用以下命令提取tar设置。
$ cd / go / to / download / path $ tar -zxf jdk-8u60-linux-x64.gz |
步骤1.3:移至opt目录
要让所有用户都可以使用Java,请将提取的Java内容移动到“/ usr / local / java”文件夹中。
$ su password: (type password of root user) $ mkdir /opt/jdk $ mv jdk-1.8.0_60 /opt/jdk/ |
步骤1.4:设置路径
要设置路径和JAVA_HOME变量,请将以下命令添加到〜/ .bashrc文件中。
导出JAVA_HOME = / usr / jdk / jdk-1.8.0_60
export PATH = $ PATH:$ JAVA_HOME / bin
现在,将所有更改应用到当前正在运行的系统中。
$ source〜/ .bashrc |
步骤1.5:Java替代品
使用以下命令更改Java选项。
update-alternatives --install / usr / bin / java java /opt/jdk/jdk1.8.0_60/bin/java 100 |
步骤1.6
使用步骤1中介绍的验证命令(java -version)验证Java安装。
第2步:ZooKeeper框架安装
步骤2.1:下载ZooKeeper
要在您的机器上安装ZooKeeper框架,请访问以下链接并下载最新版本的ZooKeeper。http://zookeeper.apache.org/releases.html
截至目前,ZooKeeper的最新版本是3.4.6(ZooKeeper-3.4.6.tar.gz)。
步骤2.2:解压tar文件
使用以下命令提取tar文件:
$ cd opt / $ tar -zxf zookeeper-3.4.6.tar.gz $ cd zookeeper-3.4.6 $ mkdir data |
步骤2.3:创建配置文件
使用vi conf / zoo.cfg命令打开名为conf / zoo.cfg的配置文件,并将所有以下参数设置为起点。
$ vi conf/zoo.cfg tickTime=2000 dataDir=/path/to/zookeeper/data clientPort=2181 initLimit=5 syncLimit=2 |
配置文件保存成功后,再次返回终端。 您现在可以启动zookeeper服务器。
步骤2.4:启动ZooKeeper服务器
执行以下命令:
$ bin / zkServer.sh start |
执行此命令后,您将得到如下响应:
$ JMX enabled by default $ Using config: /Users/../zookeeper-3.4.6/bin/../conf/zoo.cfg $ Starting zookeeper ... STARTED |
步骤2.5:启动CLI
键入以下命令:
$ bin / zkCli.sh |
输入上述命令后,您将连接到ZooKeeper服务器,并且您应该得到以下响应。
Connecting to localhost:2181 ................ ................ ................ Welcome to ZooKeeper! ................ ................ WATCHER:: WatchedEvent state:SyncConnected type: None path:null [zk: localhost:2181(CONNECTED) 0] |
停止ZooKeeper服务器
连接服务器并执行所有操作后,可以使用以下命令停止zookeeper服务器。
$ bin / zkServer.sh stop |
6 ZooKeeper CLI使用
ZooKeeper命令行界面(CLI)用于与ZooKeeper集成交互以用于开发目的。 这对调试和解决不同的选项很有用。
要执行ZooKeeper CLI操作,首先打开您的ZooKeeper服务器(“bin / zkServer.sh start”),然后打开ZooKeeper客户端(“bin / zkCli.sh”)。 客户端启动后,您可以执行以下操作:
·创建znode
·获取数据
·观察znode是否有变化
·设置数据
·创建一个znode的子节点
·列出一个znode的子节点
·检查状态
·删除/删除一个znode
现在让我们以一个例子逐一看看上面的命令。
1、创建结点
用给定的路径创建一个znode。 flag参数指定创建的znode是短暂的,持续的还是顺序的。 默认情况下,所有znode都是持久性的。
·会话过期或客户端断开连接时,临时znodes(标志:e)将自动删除。
·顺序znodes保证znode路径将是唯一的。
·ZooKeeper集合将在znode路径中添加***和10位填充字符。 例如,znode路径/ myapp将被转换为/ myapp0000000001,下一个***将为/ myapp0000000002。 如果没有标志被指定,那么znode被认为是持久的。
语法:
create /path /data |
示例
create /FirstZnode “Myfirstzookeeper-app” |
输出:
[zk: localhost:2181(CONNECTED) 0] create /FirstZnode “Myfirstzookeeper-app” Created /FirstZnode |
要创建顺序znode,请添加-s标志,如下所示。
语法:
create -s /path /data |
示例
create -s /FirstZnode second-data |
输出:
[zk: localhost:2181(CONNECTED) 2] create -s /FirstZnode “second-data” Created /FirstZnode0000000023 |
要创建一个Ephemeral znode,请添加-e标志,如下所示。
语法:
create -e /path /data |
示例
create -e /SecondZnode “Ephemeral-data” |
输出:
[zk: localhost:2181(CONNECTED) 2] create -e /SecondZnode “Ephemeral-data” Created /SecondZnode |
请记住,当客户端连接丢失时,临时znode将被删除。 您可以通过退出ZooKeeper CLI然后重新打开CLI来尝试。
Get Data
它返回指定znode的znode和元数据的关联数据。 您将获得有关数据最后修改时间,修改位置和数据信息等信息。 此CLI还用于分配手表以显示有关数据的通知。 |
语法:
get /path |
示例
get /FirstZnode |
输出:
[zk: localhost:2181(CONNECTED) 1] get /FirstZnode “Myfirstzookeeper-app” cZxid = 0x7f ctime = Tue Sep 29 16:15:47 IST 2015 mZxid = 0x7f mtime = Tue Sep 29 16:15:47 IST 2015 pZxid = 0x7f cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 22 numChildren = 0 |
要访问顺序znode,您必须输入znode的完整路径。
示例
get /FirstZnode0000000023 |
输出:
[zk: localhost:2181(CONNECTED) 1] get /FirstZnode0000000023 “Second-data” cZxid = 0x80 ctime = Tue Sep 29 16:25:47 IST 2015 mZxid = 0x80 mtime = Tue Sep 29 16:25:47 IST 2015 pZxid = 0x80 cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 13 numChildren = 0 |
Watch
当指定的znode或znode的子数据更改时,watch会显示通知。 您只能在get命令中设置watch。
语法:
get /path [watch] 1 |
示例
get /FirstZnode 1 |
输出:
[zk: localhost:2181(CONNECTED) 1] get /FirstZnode 1 “Myfirstzookeeper-app” cZxid = 0x7f ctime = Tue Sep 29 16:15:47 IST 2015 mZxid = 0x7f mtime = Tue Sep 29 16:15:47 IST 2015 pZxid = 0x7f cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 22 numChildren = 0 |
输出与普通的get命令类似,但它将等待背景中的znode更改。 <从这里开始>
Set Data
设置指定znode的数据。 完成此设置操作后,可以使用get CLI命令检查数据。
语法:
set /path /data |
示例
set /SecondZnode Data-updated |
输出:
[zk: localhost:2181(CONNECTED) 1] get /SecondZnode “Data-updated” cZxid = 0x82 ctime = Tue Sep 29 16:29:50 IST 2015 mZxid = 0x83 mtime = Tue Sep 29 16:29:50 IST 2015 pZxid = 0x82 cversion = 0 dataVersion = 1 aclVersion = 0 ephemeralOwner = 0x15018b47db00000 dataLength = 14 numChildren = 0 |
如果您在get命令中指定了watch选项(如前一个命令),那么输出将如下所示:
输出:
[zk: localhost:2181(CONNECTED) 1] get /FirstZnode “Mysecondzookeeper-app” WATCHER: : WatchedEvent state:SyncConnected type:NodeDataChanged path:/FirstZnode cZxid = 0x7f ctime = Tue Sep 29 16:15:47 IST 2015 mZxid = 0x84 mtime = Tue Sep 29 17:14:47 IST 2015 pZxid = 0x7f cversion = 0 dataVersion = 1 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 23 numChildren = 0 |
创建子结点:
创建子项与创建新的znode类似。 唯一的区别是子znode的路径也会有父路径。
语法:
create /parent/path/subnode/path /data |
示例
create /FirstZnode/Child1 firstchildren |
输出:
[zk: localhost:2181(CONNECTED) 16] create /FirstZnode/Child1 “firstchildren” created /FirstZnode/Child1 [zk: localhost:2181(CONNECTED) 17] create /FirstZnode/Child2 “secondchildren” created /FirstZnode/Child2 |
列出子结点
该命令用于列出和显示znode的子节点。
语法:
ls /path |
示例
ls /MyFirstZnode |
输出:
[zk: localhost:2181(CONNECTED) 2] ls /MyFirstZnode [mysecondsubnode, myfirstsubnode] |
检查状态:
状态描述了指定znode的元数据。 它包含诸如时间戳,版本号,ACL,数据长度和子节点等详细信息。
语法:
stat /path |
示例
stat /FirstZnode |
输出:
[zk: localhost:2181(CONNECTED) 1] stat /FirstZnode cZxid = 0x7f ctime = Tue Sep 29 16:15:47 IST 2015 mZxid = 0x7f mtime = Tue Sep 29 17:14:24 IST 2015 pZxid = 0x7f cversion = 0 dataVersion = 1 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 23 numChildren = 0 |
删除一个结点
删除指定的znode并递归地删除其所有子节点。 只有当这样的znode可用时才会发生这种情况。
语法:
rmr /path |
示例
rmr /FirstZnode |
输出:
[zk: localhost:2181(CONNECTED) 10] rmr /FirstZnode [zk: localhost:2181(CONNECTED) 11] get /FirstZnode Node does not exist: /FirstZnode |
删除(删除/路径)命令与删除命令类似,只是它仅适用于没有子节点的znode。
7 ZooKeeper API介绍
ZooKeeper为Java和C提供了官方的API绑定。ZooKeeper社区为大多数语言(.NET,python等)提供了非官方的API。 使用ZooKeeper API,应用程序可以连接,交互,操作数据,协调并最终断开与ZooKeeper集成的连接。
ZooKeeper API具有丰富的功能,以简单安全的方式获得ZooKeeper集成的所有功能。 ZooKeeper API提供了同步和异步方法。
ZooKeeper集成和ZooKeeper API在各个方面完全相互补充,它以一种很好的方式使开发人员受益。 让我们在本章中讨论Java绑定。
1、ZooKeeper API的基础知识
与ZooKeeper集成交互的应用程序被称为ZooKeeper客户端或简称为客户端。
Znode是ZooKeeper集成的核心组件,ZooKeeper API提供了一小组方法来操作ZooKeeper集成的所有znode细节。
客户应遵循以下步骤与ZooKeeper合奏进行清晰而干净的互动。
·连接到ZooKeeper整体。 ZooKeeper集合为客户端分配一个会话ID。
·定期向服务器发送检测信号。 否则,ZooKeeper集合将会话ID过期并且客户端需要重新连接。
·只要会话ID处于活动状态,就可以获取/设置znode。
·完成所有任务后,断开与ZooKeeper集成的连接。 如果客户端长时间处于非活动状态,那么ZooKeeper集合将自动断开客户端连接。
2、Java绑定
让我们来理解本章中最重要的一组ZooKeeper API。 ZooKeeper API的核心部分是ZooKeeper类。 它提供了在其构造函数中连接ZooKeeper集合的选项,并具有以下方法:
·connect - 连接到ZooKeeper集合
·create - 创建一个znode
·exists - 检查是否存在znode及其信息
·getData - 从特定的znode获取数据
·setData - 在特定的znode中设置数据
·getChildren - 获取特定znode中的所有子节点
·delete - 获取特定的znode及其所有子节点
·close - 关闭连接
3、连接到ZooKeeper集群
ZooKeeper类通过其构造函数提供连接功能。 构造函数的签名如下所示:
ZooKeeper(String connectionString, int sessionTimeout, Watcher watcher) |
在这里,
·connectionString – ZooKeeper集群。
·sessionTimeout - 以毫秒为单位的会话超时。
·watcher - 实现“观察者”接口的对象。 ZooKeeper集合通过观察器对象返回连接状态。
让我们创建一个新的帮助类ZooKeeperConnection并添加一个连接方法。 connect方法创建一个ZooKeeper对象,连接到ZooKeeper集合,然后返回该对象。
这里CountDownLatch用于停止(等待)主进程,直到客户端连接到ZooKeeper集合。
ZooKeeper集群通过Watcher回调回复连接状态。 一旦客户端连接到ZooKeeper集合并且Watcher回调调用CountDownLatch的countDown方法释放锁定,则在主进程中等待,Watcher回调将被调用。
以下是与ZooKeeper集成连接的完整代码。
Coding: ZooKeeperConnection.java
// import java classes import java.io.IOException; import java.util.concurrent.CountDownLatch; // import zookeeper classes import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.KeeperState; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.AsyncCallback.StatCallback; import org.apache.zookeeper.KeeperException.Code; import org.apache.zookeeper.data.Stat;
public class ZooKeeperConnection {
// declare zookeeper instance to access ZooKeeper ensemble private ZooKeeper zoo; final CountDownLatch connectedSignal = new CountDownLatch(1);
// Method to connect zookeeper ensemble. public ZooKeeper connect(String host) throws IOException,InterruptedException { zoo = new ZooKeeper(host,5000,new Watcher() { public void process(WatchedEvent we) { if (we.getState() == KeeperState.SyncConnected) { connectedSignal.countDown(); } } }); connectedSignal.await(); return zoo; }
// Method to disconnect from zookeeper server public void close() throws InterruptedException { zoo.close(); } } |
保存上面的代码,它将在下一节中用于连接ZooKeeper集群。
4、创建一个子结点
ZooKeeper类提供了create方法来在ZooKeeper集合中创建一个新的znode。 create方法的签名如下所示:
create(String path, byte[] data, List<ACL> acl, CreateMode createMode) |
在这里,
·path - Znode路径。 例如,/ myapp1,/ myapp2,/ myapp1 / mydata1,myapp2 / mydata1 / myanothersubdata
·data - 要存储在指定的znode路径中的数据
·acl - 要创建的节点的访问控制列表。 ZooKeeper API提供了一个静态接口ZooDefs.Ids来获取一些基本的acl列表。 例如,ZooDefs.Ids.OPEN_ACL_UNSAFE返回打开的znode的acl列表。
·createMode - 节点的类型,既可以是短暂的,也可以是顺序的,或者两者兼有。 这是一个枚举。
让我们创建一个新的Java应用程序来检查ZooKeeper API的创建功能。 创建一个文件ZKCreate.java。 在主要方法中,创建一个类型为ZooKeeperConnection的对象,并调用connect方法连接到ZooKeeper集合。
connect方法将返回ZooKeeper对象zk。 现在,使用自定义路径和数据调用zk对象的创建方法。
创建znode的完整程序代码如下所示:
Coding: ZKCreate.java
import java.io.IOException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.KeeperState; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.ZooDefs;
public class ZKCreate { // create static instance for zookeeper class. private static ZooKeeper zk; // create static instance for ZooKeeperConnection class. private static ZooKeeperConnection conn; // Method to create znode in zookeeper ensemble
public static void create(String path, byte[] data) throws KeeperException,InterruptedException { zk.create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); }
public static void main(String[] args){ // znode path String path = "/MyFirstZnode"; // Assign path to znode // data in byte array byte[] data = "My first zookeeper app”.getBytes(); // Declare data try { conn = new ZooKeeperConnection(); zk = conn.connect("localhost"); create(path, data); // Create the data to the specified path conn.close(); } catch (Exception e) { System.out.println(e.getMessage()); //Catch error message } } } |
一旦应用程序被编译并执行,将在ZooKeeper集合中创建一个具有指定数据的znode。 您可以使用ZooKeeper CLI zkCli.sh进行检查。
cd /path/to/zookeeper bin/zkCli.sh >>> get /MyFirstZnode |
5、Exists(检查Znode是否存在)
ZooKeeper类提供了用于检查znode是否存在的exists方法。 如果指定的znode存在,它将返回znode的元数据。 存在方法的签名如下所示:
exists(String path, boolean watcher) |
在这里,
·path - Znode路径
·watcher - 布尔值,指定是否观看指定的znode
让我们创建一个新的Java应用程序来检查ZooKeeper API的“存在”功能。 创建一个文件“ZKExists.java”。 在主要方法中,使用“ZooKeeperConnection”对象创建ZooKeeper对象“zk”。 然后,用自定义的“路径”调用“zk”对象的“exists”方法。 完整的清单如下
Coding: ZKExists.java
import java.io.IOException; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.KeeperState; import org.apache.zookeeper.data.Stat;
public class ZKExists {
private static ZooKeeper zk; private static ZooKeeperConnection conn;
// Method to check existence of znode and its status, if znode is available. public static Stat znode_exists(String path) throws KeeperException,InterruptedException { return zk.exists(path, true); }
public static void main(String[] args) throws InterruptedException,KeeperException { String path= "/MyFirstZnode"; // Assign znode to the specified path try { conn = new ZooKeeperConnection(); zk = conn.connect("localhost"); Stat stat = znode_exists(path); // Stat checks the path of the znode if(stat!= null) { System.out.println("Node exists and the node version is " + stat.getVersion()); } else { System.out.println("Node does not exists"); } } catch(Exception e) { System.out.println(e.getMessage()); // Catches error messages } } } |
一旦应用程序被编译并执行,您将获得下面的输出。
Node exists and the node version is 1. |
6、 getData方法
ZooKeeper类提供getData方法来获取附加在指定znode中的数据
和它的地位。 getData方法的签名如下所示:
getData(String path, Watcher watcher, Stat stat) |
在这里,
· path – Znode的path
·watcher - 类型Watcher的回调函数。 当指定的znode的数据发生变化时,ZooKeeper整体将通知通过Watcher回调。 这是一次性通知。
·stat - 返回znode的元数据。
让我们创建一个新的Java应用程序来理解ZooKeeper API的getData功能。 创建一个文件ZKGetData.java。 在主要方法中,使用ZooKeeperConnection对象创建一个ZooKeeper对象zk。 然后,用自定义路径调用zk对象的getData方法。
以下是从指定节点获取数据的完整程序代码:
Coding: ZKGetData.java
import java.io.IOException; import java.util.concurrent.CountDownLatch; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.KeeperState; import org.apache.zookeeper.data.Stat;
public class ZKGetData {
private static ZooKeeper zk; private static ZooKeeperConnection conn;
public static Stat znode_exists(String path) throws KeeperException,InterruptedException { return zk.exists(path,true); }
public static void main(String[] args) throws InterruptedException, KeeperException { String path = "/MyFirstZnode"; final CountDownLatch connectedSignal = new CountDownLatch(1); try { conn = new ZooKeeperConnection(); zk = conn.connect("localhost"); Stat stat = znode_exists(path); if(stat != null) { byte[] b = zk.getData(path, new Watcher() { public void process(WatchedEvent we) { if (we.getType() == Event.EventType.None) { switch(we.getState()) { case Expired: connectedSignal.countDown(); break; } } else { String path = "/MyFirstZnode"; try { byte[] bn = zk.getData(path,false, null); String data = new String(bn,"UTF-8"); System.out.println(data); connectedSignal.countDown(); } catch(Exception ex) { System.out.println(ex.getMessage()); } } } }, null); String data = new String(b, "UTF-8"); System.out.println(data); connectedSignal.await(); } else { System.out.println("Node does not exists"); } } catch(Exception e) { System.out.println(e.getMessage()); } } } |
一旦应用程序被编译并执行,您将获得下面的输出。
My first zookeeper app |
应用程序将等待来自ZooKeeper集体的进一步通知。 使用ZooKeeper CLI zkCli.sh改变指定的znode的数据。
cd / path / to / zookeeper bin/ zkCli.sh >>> set / MyFirstZnode Hello |
现在,应用程序将打印以下输出并退出。
Hello |
7、setData方法
ZooKeeper类提供setData方法来修改附加在指定znode中的数据。
setData方法的签名如下所示:
setData(String path, byte[] data, int version) |
在这里,
·path - Znode路径
·data - 要存储在指定的znode路径中的数据。
·version - znode的当前版本。 ZooKeeper更新的版本号
znode只要数据发生变化。
现在让我们创建一个新的Java应用程序来理解ZooKeeper API的setData功能。 创建一个文件ZKSetData.java。 在主要方法中,使用ZooKeeperConnection对象创建一个ZooKeeper对象zk。 然后,用指定的路径,新数据和节点版本调用zk对象的setData方法。
以下是完整的程序代码,用于修改指定znode中附加的数据。
Code: ZKSetData.java
import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.KeeperState; import java.io.IOException;
public class ZKSetData {
private static ZooKeeper zk; private static ZooKeeperConnection conn;
// Method to update the data in a znode. Similar to getData but without watcher. public static void update(String path, byte[] data) throws KeeperException,InterruptedException { zk.setData(path, data, zk.exists(path,true).getVersion()); }
public static void main(String[] args) throws InterruptedException,KeeperException { String path= "/MyFirstZnode"; byte[] data = "Success".getBytes(); //Assign data which is to be updated. try { conn = new ZooKeeperConnection(); zk = conn.connect("localhost"); update(path, data); // Update znode data to the specified path } catch(Exception e) { System.out.println(e.getMessage()); } } } |
一旦应用程序被编译并执行,指定znode的数据将被更改,并且可以使用ZooKeeper CLI zkCli.sh进行检查。
cd /path/to/zookeeper bin/zkCli.sh >>> get /MyFirstZnode |
8、getChildren方法
ZooKeeper类提供getChildren方法来获取特定znode的所有子节点。
getChildren方法的签名如下所示:
getChildren(String path, Watcher watcher) |
在这里,
·path - Znode路径。
·watcher - 类型为“观察者”的回调函数。 ZooKeeper集合将在何时通知
指定的znode被删除或者znode下的一个子节点被创建/删除。 这个
是一次性通知。
Coding: ZKGetChildren.java
import java.io.IOException; import java.util.*; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.KeeperState; import org.apache.zookeeper.data.Stat;
public class ZKGetChildren {
private static ZooKeeper zk; private static ZooKeeperConnection conn;
// Method to check existence of znode and its status, if znode is available. public static Stat znode_exists(String path) throws KeeperException,InterruptedException { return zk.exists(path,true); }
public static void main(String[] args) throws InterruptedException,KeeperException { String path= "/MyFirstZnode"; // Assign path to the znode try { conn = new ZooKeeperConnection(); zk = conn.connect("localhost"); Stat stat = znode_exists(path); // Stat checks the path if(stat!= null) { //“getChildren” method- get all the children of znode.It has two args, path and watch List<String> children = zk.getChildren(path, false); for(int i = 0; i < children.size(); i++) System.out.println(children.get(i)); //Print children's } else { System.out.println("Node does not exists"); } } catch(Exception e) { System.out.println(e.getMessage()); } } } |
在运行该程序之前,让我们使用。为/ MyFirstZnode创建两个子节点
ZooKeeper CLI,zkCli.sh。
cd /path/to/zookeeper bin/zkCli.sh >>> create /MyFirstZnode/myfirstsubnode Hi >>> create /MyFirstZnode/mysecondsubmode Hi |
现在,编译并运行该程序将输出上面创建的znode。
myfirstsubnode mysecondsubnode |
9、Delete方法
ZooKeeper类提供删除方法来删除指定的znode。 删除方法的签名如下所示:
delete(String path, int version) |
在这里,
·path - Znode路径。
·version - znode的当前版本。
让我们创建一个新的Java应用程序来理解ZooKeeper API的删除功能。 创建一个文件ZKDelete.java。 在主要方法中,使用ZooKeeperConnection对象创建一个ZooKeeper对象zk。 然后,用指定的路径和节点版本调用zk对象的delete方法。
删除znode的完整程序代码如下所示:
Coding: ZKDelete.java
import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.KeeperException;
public class ZKDelete {
private static ZooKeeper zk; private static ZooKeeperConnection conn;
// Method to check existence of znode and its status, if znode is available. public static void delete(String path) throws KeeperException,InterruptedException { zk.delete(path,zk.exists(path,true).getVersion()); }
public static void main(String[] args) throws InterruptedException,KeeperException { String path= "/MyFirstZnode"; //Assign path to the znode try{ conn = new ZooKeeperConnection(); zk = conn.connect("localhost"); delete(path); //delete the node with the specified path } catch(Exception e) { System.out.println(e.getMessage()); // catches error messages } } } |
8 ZooKeeper 应用
Zookeeper为分布式环境提供了一个灵活的协调基础设施。 ZooKeeper框架支持许多当今最好的工业应用程序。我们将在本章中讨论一些ZooKeeper最显着的应用。
Yahoo!
ZooKeeper框架最初是在“Yahoo!”中构建的。设计良好的分布式应用程序需要满足数据透明性,更好的性能,健壮性,集中配置和协调等要求。所以,他们设计了ZooKeeper框架来满足这些要求。
Apache Hadoop
Apache Hadoop是大数据行业发展的推动力。 Hadoop依靠ZooKeeper进行配置管理和协调。让我们通过一个场景来了解ZooKeeper在Hadoop中的角色。
假设一个Hadoop集群桥接了100个或更多的商品服务器。因此,需要协调和命名服务。由于涉及大量节点的计算,每个节点需要彼此同步,知道在哪里访问服务,并知道如何配置它们。目前,Hadoop集群需要跨节点服务。 ZooKeeper提供跨节点同步功能,并确保跨Hadoop项目的任务被序列化和同步。
多个ZooKeeper服务器支持大型Hadoop集群。每台客户机与ZooKeeper服务器之一进行通信以检索和更新其同步信息。一些实时示例是:
·人类基因组计划 - 人类基因组计划包含数TB的数据。
Hadoop MapReduce框架可用于分析数据集并找出人类发展的有趣事实。
·医疗保健 - 医院可以存储,检索和分析大量病人医疗记录,这些记录通常以兆兆字节为单位。
Apache HBase
Apache HBase是一个开源的,分布式的NoSQL数据库,用于实时读取/写入大型数据集并在HDFS上运行。 HBase采用主从架构,HBase Master管理所有从属设备。 从属被称为区域服务器。
HBase分布式应用程序安装依赖于正在运行的ZooKeeper集群。 Apache HBase使用ZooKeeper通过集中配置管理和分布式互斥机制来跟踪主服务器和区域服务器中分布式数据的状态。 以下是HBase的一些使用案例:
·电信 - 电信行业存储数十亿移动通话记录(约30TB /月)
并实时访问这些通话记录成为一项艰巨的任务。 HBase可以用来实时,轻松,高效地处理所有记录。
·社交网络 - 与电信行业类似,Twitter,LinkedIn和Facebook等网站通过用户创建的帖子收到大量数据。 HBase可以用来发现最近的趋势和其他有趣的事实。
Apache Solr
Apache Solr是一个用Java编写的快速,开源的搜索平台。它是一个快速,容错的分布式搜索引擎。它建立在Lucene之上,是一个高性能,功能全面的文本搜索引擎。 Solr广泛使用了ZooKeeper的各项功能,如配置管理,领导选举,节点管理,数据锁定和同步。
Solr有两个不同的部分,索引和搜索。索引是一种以适当格式存储数据以便稍后可以搜索的过程。 Solr使用ZooKeeper为多个节点中的数据建立索引并从多个节点进行搜索。 ZooKeeper提供以下功能:
·根据需要添加/删除节点
·在节点之间复制数据并随后最大限度地减少数据丢失
·在多个节点之间共享数据,然后从多个节点搜索以获得更快的搜索结果
Apache Solr的一些使用案例包括电子商务,求职等。