ZooKeeper 基础知识、部署和应用程序

简介

让咱们首先讨论一下为何想使用 ZooKeeper。ZooKeeper 是一个面向分布式系统的构建块。当设计一个分布式系统时,通常须要设计和开发一些协调服务:php

  • 名称服务— 名称服务是将一个名称映射到与该名称有关联的一些信息的服务。电话目录是将人的名字映射到其电话号码的一个名称服务。一样,DNS 服务也是一个名称服务,它将一个域名映射到一个 IP 地址。在分布式系统中,您可能想跟踪哪些服务器或服务在运行,并经过名称查看其状态。ZooKeeper 暴露了一个简单的接口来完成此工做。也能够将名称服务扩展到组成员服务,这样就能够得到与正在查找其名称的实体有关联的组的信息。
  • 锁定— 为了容许在分布式系统中对共享资源进行有序的访问,可能须要实现分布式互斥(distributed mutexes)。ZooKeeper 提供一种简单的方式来实现它们。
  • 同步— 与互斥同时出现的是同步访问共享资源的需求。不管是实现一个生产者-消费者队列,仍是实现一个障碍,ZooKeeper 都提供一个简单的接口来实现该操做。您能够在 Apache ZooKeeper 维基上查看示例,了解如何作到这一点(参阅 参考资料)。
  • 配置管理— 您可使用 ZooKeeper 集中存储和管理分布式系统的配置。这意味着,全部新加入的节点都将在加入系统后就能够当即使用来自 ZooKeeper 的最新集中式配置。这还容许您经过其中一个 ZooKeeper 客户端更改集中式配置,集中地更改分布式系统的状态。
  • 领导者选举— 分布式系统可能必须处理节点停机的问题,您可能想实现一个自动故障转移策略。ZooKeeper 经过领导者选举对此提供现成的支持。

虽然能够从头开始设计和实现全部这些服务,但调试任何问题、竞争条件或死锁都须要执行额外的工做,而且很难实现。就像您不会在代码中随处编写本身的随机数发生器或哈希函数同样,这里有一个要求:人们不该该在每次有须要时就处处从头编写本身的名称服务或领导者选举服务。此外,您能够相对容易地一块儿解决一个很是简单的组成员服务,可是,要编写它们来提供可靠性、复制和可扩展性,可能须要作更多的工做。这致使了 Apache ZooKeeper 的开发和开源,Apache ZooKeeper 是一个针对分布式系统的、开箱即用的、可靠的、可扩展的、高性能的协调服务。html

InfoSphere® BigInsights™ Quick Start Edition 是 IBM 的大数据产品,以开源的 Apache Hadoop 项目为基础。它包括 ZooKeeper 和其余大数据技术,以及增长了该平台的价值的 IBM 技术。在本文中,咱们只是使用了 ZooKeeper,可是,如欲了解有关 InfoSphere BigInsights 的更多信息,请参阅 参考资料,其中包括一个下载产品的连接。java

ZooKeeper 虽然是一个针对分布式系统的协调服务,但它自己也是一个分布式应用程序。ZooKeeper 遵循一个简单的客户端-服务器模型,其中客户端 是使用服务的节点(即机器),而服务器 是提供服务的节点。ZooKeeper 服务器的集合造成了一个 ZooKeeper 集合体(ensemble)。在任何给定的时间内,一个 ZooKeeper 客户端可链接到一个 ZooKeeper 服务器。每一个 ZooKeeper 服务器均可以同时处理大量客户端链接。每一个客户端按期发送 ping 到它所链接的 ZooKeeper 服务器,让服务器知道它处于活动和链接状态。被询问的 ZooKeeper 服务器经过 ping 确认进行响应,表示服务器也处于活动状态。若是客户端在指定时间内没有收到服务器的确认,那么客户端会链接到集合体中的另外一台服务器,并且客户端会话会被透明地转移到新的 ZooKeeper 服务器。node

图 1 描述了 ZooKeeper 的客户端-服务器架构。git

图 1. ZooKeeper 的客户端-服务器架构github

图像显示了 ZooKeeper 的客户端-服务器架构

ZooKeeper 有一个相似于文件系统的数据模型,由 znodes 组成。能够将 znodes(ZooKeeper 数据节点)视为相似 UNIX 的传统系统中的文件,但它们能够有子节点。另外一种方式是将它们视为目录,它们能够有与其相关的数据。每一个这些目录都被称为一个 znode。图 2 显示的图表明与两个城市中的运动队相同的层次结构。web

图 2. 该图表示了两个城市中的运动队的层次结构数据库

图像显示了两个城市中的运动队的层次结构

znode 层次结构被存储在每一个 ZooKeeper 服务器的内存中。这实现了对来自客户端的读取操做的可扩展的快速响应。每一个 ZooKeeper 服务器还在磁盘上维护了一个事务日志,记录全部的写入请求。由于 ZooKeeper 服务器在返回一个成功的响应以前必须将事务同步到磁盘,因此事务日志也是 ZooKeeper 中对性能最重要的组成部分。能够存储在 znode 中的数据的默认最大大小为 1 MB。所以,即便 ZooKeeper 的层次结构看起来与文件系统类似,也不该该将它用做一个通用的文件系统。相反,应该只将它用做少许数据的存储机制,以便为分布式应用程序提供可靠性、可用性和协调。apache

当客户端请求读取特定 znode 的内容时,读取操做是在客户端所链接的服务器上进行的。所以,因为只涉及集合体中的一个服务器,因此读取是快速和可扩展的。然而,为了成功完成写入操做,要求 ZooKeeper 集合体的严格意义上的多数节点都是可用的。在启动 ZooKeeper 服务时,集合体中的某个节点被选举为领导者。当客户端发出一个写入请求时,所链接的服务器会将请求传递给领导者。此领导者对集合体的全部节点发出相同的写入请求。若是严格意义上的多数节点(也被称为法定数量(quorum))成功响应该写入请求,那么写入请求被视为已成功完成。而后,一个成功的返回代码会返回给发起写入请求的客户端。若是集合体中的可用节点数量未达到法定数量,那么 ZooKeeper 服务将不起做用。安全

InfoSphere BigInsights Quick Start Edition

ZooKeeper 是 InfoSphere BigInsights(IBM 基于 Hadoop 的产品)中的一个组件。Quick Start Edition 是一个免费的、可下载的 InfoSphere BigInsights 版本。使用 Quick Start Edition,您能够尝试使用 ZooKeeper 和 IBM 开发的特性来提升开源 Hadoop 的价值,好比 Big SQL、文本分析和 BigSheets。引导式学习可以让您的体验尽量地顺畅,包括循序渐进、自订进度的教程和视频,可帮助您开始让 Hadoop 为您所用。没有时间或数据限制,您能够自行安排时间,在大量数据上试验。请 观看视频学习教程(PDF) 和 马上下载 BigInsights Quick Start Edition

法定数量是经过严格意义上的多数节点来表示的。在集合体中,能够包含一个节点,但它不是一个高可用和可靠的系统。若是在集合体中有两个节点,那么这两个节点都必须已经启动并让服务正常运行,由于两个节点中的一个并非严格意义上的多数。若是在集合体中有三个节点,即便其中一个停机了,您仍然能够得到正常运行的服务(三个中的两个是严格意义上的多数)。出于这个缘由,ZooKeeper 的集合体中一般包含奇数数量的节点,由于就容错而言,与三个节点相比,四个节点并不占优点,由于只要有两个节点停机,ZooKeeper 服务就会中止。在有五个节点的集群上,须要三个节点停机才会致使 ZooKeeper 服务中止运做。

如今,咱们已经清楚地了解到,节点数量应该是奇数,让咱们再来思考一下 ZooKeeper 集合体中须要有多少个节点。读取操做始终从链接到客户端的 ZooKeeper 服务器读取数据,因此它们的性能不会随着集合体中的服务器数量额变化而变化。可是,仅在写入法定数量的节点时,写入操做才是成功的。这意味着,随着在集合体中的节点数量的增长,写入性能会降低,由于必须将写入内容写入到更多的服务器中,并在更多服务器之间进行协调。

ZooKeeper 的美妙之处在于,想运行多少服务器彻底由您本身决定。若是想运行一台服务器,从 ZooKeeper 的角度来看是没问题的;只是您的系统再也不是高度可靠或高度可用的。三个节点的 ZooKeeper 集合体支持在一个节点故障的状况下不丢失服务,这对于大多数用户而言,这多是没问题的,也能够说是最多见的部署拓扑。不过,为了安全起见,能够在您的集合体中使用五个节点。五个节点的集合体让您能够拿出一台服务器进行维护或滚动升级,并可以在不中断服务的状况下承受第二台服务器的意外故障。

所以,在 ZooKeeper 集合体中,3、五或七是最典型的节点数量。请记住,ZooKeeper 集合体的大小与分布式系统中的节点大小没有什么关系。分布式系统中的节点将是 ZooKeeper 集合体的客户端,每一个 ZooKeeper 服务器都可以以可扩展的方式处理大量客户端。例如,HBase(Hadoop 上的分布式数据库)依赖​​于 ZooKeeper 实现区域服务器的领导者选举和租赁管理。您能够利用一个相对较少(好比说,五个)节点的 ZooKeeper 集合体运行有 50 个节点的大型 HBase 集群。

设置并部署 ZooKeeper 集合体

如今让咱们设置并部署有三个节点的 ZooKeeper 集合体。在这里,咱们将使用撰写本文时的最新版的 ZooKeeper:3.4.5(请参阅 参考资料 得到有关的下载信息)。咱们用于此演示的节点被命名为 zkserver1.mybiz.com、zkserver2.mybiz.com 和 zk3server3.mybiz.com。必须在每一个节点上遵循下面的步骤来启动 ZooKeeper 服务器:

  1. 若是还没有安装 JDK,请下载安装它(参阅 参考资料)。这是必需的,由于 ZooKeeper 服务器在 JVM 上运行。
  2. 下载 ZooKeeper 3.4.5. tar.gz tarball 并将它解压缩到适当的位置。

    清单 1. 下载 ZooKeeper tarball 并将它解压缩到适当的位置

    1

    2

    3

    wget

    http://www.bizdirusa.com/mirrors/apache/ZooKeeper/stable/zookeeper3.4.5.

    tar.gz tar xzvf zookeeper3.4.5.tar.gz

  3. 建立一个目录,用它来存储与 ZooKeeper 服务器有关联的一些状态:mkdir /var/lib/zookeeper。您可能须要将这个目录建立为根目录,并在之后将这个目录的全部者更改成您但愿运行 ZooKeeper 服务器的用户。
  4. 设置配置。建立或编辑 zookeeper3.4.5/conf/zoo.cfg 文件,使其与 清单 2 类似。

    清单 2. 设置配置

    1

    2

    3

    4

    5

    6

    tickTime=2000

    dataDir=/var/lib/zookeeper clientPort=2181

    initLimit=5 syncLimit=2

    server.1=zkserver1.mybiz.com:2888:3888

    server.2=zkserver2.mybiz.com:2888:3888

    server.3=zkserver3.mybiz.com:2888:3888


    值得重点注意的一点是,全部三个机器都应该打开端口 218一、2888 和 3888。在本例中,端口 2181 由 ZooKeeper 客户端使用,用于链接到 ZooKeeper 服务器;端口 2888 由对等 ZooKeeper 服务器使用,用于互相通讯;而端口 3888 用于领导者选举。您能够选择本身喜欢的任何端口。一般建议在全部 ZooKeeper 服务器上使用相同的端口。
  5. 建立一个 /var/lib/zookeeper/myid 文件。此文件的内容将只包含 zkserver1.mybiz.com 上的数字 一、zkserver2.mybiz.com 上的数字 2 和 zkserver3.mybiz.com 上的数字 3。清单 3 显示了来自 zkserver1.mybiz.com 的此文件的 cat 输出。

    清单 3. cat 输出

    1

    2

    mark@zkserver1.mybiz.com:~# cat

    /var/lib/zookeeper/myid 1


    如今,您已经作好了在每台机器上启动 ZooKeeper 服务器的准备。

    清单 4. 启动 ZooKeeper 服务器

    1

    2

    zookeeper3.4.5/ bin/zkServer.sh

    start


    如今,您能够从其中一台正在运行 ZooKeeper 服务器的机器上启动一个 CLI 客户端。

    清单 5. 启动 CLI 客户端

    1

    2

    zookeeper3.4.5/ bin/zkCli.sh server

    zkserver1.mybiz.com:2181,zkserver2.mybiz.com:2181,zkserver3.mybiz.com:2181


    客户端提供一个服务器列表,能够任意选中一个进行链接。若是在链接过程当中失去与该服务器的链接,则会选中列表中的另外一台服务器,并且客户端会话也会转移到该服务器。一旦启动了客户端,您就能够建立、编辑和删除 znode。让咱们在 /mynode 建立一个znode,使用 helloworld 做为关联的数据。

    清单 6. 在 /mynode 上建立一个 znode

    1

    2

    [zk:127.0.0.1:2181(CONNECTED) 2] create /mynode

    helloworld Created /mynode


    如今,让咱们在 /mynode 验证和检索数据。

    清单 7. 在 /mynode 验证和检索数据

    1

    2

    3

    4

    5

    6

    7

    [zk:127.0.0.1:2181(CONNECTED) 6] get /mynode

    helloworld cZxid = 0x200000005 ctime = Sat Jul 20

    19:53:52 PDT 2013 mZxid = 0x200000005 mtime = Sat

    Jul 20 19:53:52 PDT 2013 pZxid = 0x200000005

    cversion = 0 dataVersion = 0 aclVersion = 0

    ephemeralOwner = 0x0 dataLength = 11 numChildren =

    0


    您会发现,在获取一个 znode 数据时,客户端也返回了一些与 znode 有关的元数据。此元数据中的一些重要字段包括,与建立和最后修改 znode 的时间有关的阶段时间戳(ctime 和 mtime)、每次修改数据都会更改的数据版本(dataVersion)、数据长度(dataLength)、这个 znode 的子节点的数量(numChildren)。咱们如今能够删除 znode。

    清单 8. 删除 znode

    1

    2

    [zk:127.0.0.1:2181(CONNECTED) 7]

    rmr /mynode


    让咱们在 /mysecondnode 建立另外一个 znode。

    清单 9. 建立另外一个 znode

    1

    2

    [zk:127.0.0.1:2181(CONNECTED) 10] create

    /mysecondnode hello Created /mysecondnode


    如今,让咱们在 /mysecondnode 验证和检索数据。这一次,咱们在最后提供了一个可选参数 1。此参数为 /mysecondnode 上的数据设置了一个一次性的触发器(名称为 watch)。若是另外一个客户端在 /mysecondnode 上修改数据,该客户端将会得到一个异步通知。请注意,该通知只发送一次,除非 watch 被从新设置,不然不会因数据发生改变而再次发送通知。

    清单 10. 在 /mysecondnode 上验证和检索数据

    1

    2

    3

    4

    5

    6

    7

    [zk:127.0.0.1:2181(CONNECTED) 12] get

    /mysecondnode 1 hello cZxid = 0x200000007 ctime =

    Sat Jul 20 19:58:27 PDT 2013 mZxid = 0x200000007

    mtime = Sat Jul 20 19:58:27 PDT 2013 pZxid =

    0x200000007 cversion = 0 dataVersion = 0

    aclVersion = 0 ephemeralOwner = 0x0 dataLength = 5

    numChildren = 0


    如今,从不一样的客户端(好比,从不一样的机器)更改与 /mysecondnode 有关联的数据的值。

    清单 11. 更改与 /mysecondnode 有关联的数据的值

    1

    2

    3

    4

    5

    6

    7

    [zk: localhost:2181(CONNECTED)

    1] set /mysecondnode hello2 cZxid = 0x200000007

    ctime = Sat Jul 20 19:58:27 PDT 2013 mZxid =

    0x200000009 mtime = Sat Jul 20 20:02:37 PDT 2013

    pZxid = 0x200000007 cversion = 0 dataVersion = 1

    aclVersion = 0 ephemeralOwner = 0x0 dataLength = 6

    numChildren = 0


    您会发现,在第一个客户端上得到了一个 watch 通知。

    清单 12. 在第一个客户端上得到了一个 watch 通知

    1

    2

    3

    [zk:127.0.0.1:2181(CONNECTED) 13] WATCHER::

    WatchedEvent state:SyncConnected

    type:NodeDataChanged path:/mysecondnode


    继续下去,由于 znode 造成了一个分层命名空间,因此您还能够建立子节点。 

    清单 13. 建立子节点

    1

    2

    3

    [zk:

    localhost:2181(CONNECTED) 2] create /mysecondnode/

    subnode 123 Created /mysecondnode/ subnode


    您能够得到关于某个 znode 的其余统计元数据。 

    清单 14. 得到关于某个 znode 的其余统计元数据

    1

    2

    3

    4

    5

    6

    7

    [zk:127.0.0.1:2181(CONNECTED)

    14] stat /mysecondnode cZxid = 0x200000007 ctime =

    Sat Jul 20 19:58:27 PDT 2013 mZxid = 0x200000009

    mtime = Sat Jul 20 20:02:37 PDT 2013 pZxid =

    0x20000000a cversion = 1 dataVersion = 1

    aclVersion = 0 ephemeralOwner = 0x0 dataLength = 6

    numChildren = 1

在上面的示例中,咱们使用了 ZooKeeper 的 CLI 客户端与 ZooKeeper 服务器进行交互。ZooKeeper 提供了 Java™、C、Python 和其余绑定。您能够经过这些绑定调用客户端 API,将 Java、C 或 Python 应用程序转换为 ZooKeeper 客户端。

ZooKeeper 的应用程序

因为 ZooKeeper 在分布式系统中提供了一些多功能的用例,ZooKeeper 有一组不一样的实用应用程序。咱们将在这里列出部分这些应用程序。这些应用程序大多取自 Apache ZooKeeper 维基,那里还提供了一个更完整的最新列表。请参阅 参考资料,得到这些技术的连接:

  • Apache Hadoop 依靠 ZooKeeper 来实现 Hadoop HDFS NameNode 的自动故障转移,以及 YARN ResourceManager 的高可用性。
  • Apache HBase 是构建于 Hadoop 之上的分布式数据库,它使用 ZooKeeper 来实现区域服务器的主选举(master election)、租赁管理以及区域服务器之间的其余通讯。
  • Apache Accumulo 是构建于 Apache ZooKeeper(和 Apache Hadoop)之上的另外一个排序分布式键/值存储。
  • Apache Solr 使用 ZooKeeper 实现领导者选举和集中式配置。
  • Apache Mesos 是一个集群管理器,提供了分布式应用程序之间高效的资源隔离和共享。Mesos 使用 ZooKeeper 实现了容错的、复制的主选举。
  • Neo4j 是一个分布式图形数据库,它使用 ZooKeeper 写入主选择和读取从协调(read slave coordination)。
  • Cloudera Search 使用 ZooKeeper(经过 Apache Solr)集成了搜索功能与 Apache Hadoop,以实现集中式配置管理。

结束语

实现您本身的协议来协调分布式系统,这多是一个使人感到沮丧的费时的过程。这正是 ZooKeeper 发挥其做用的地方。ZooKeeper 是一个稳定的、简单的、高性能的协调服务,为您提供编写正确的分布式应用程序所需的工具,而无需担忧竞争条件、死锁和不一致。在下一次编写分布式应用程序时,您就能够利用 ZooKeeper 支持全部协调需求。

相关主题

相关文章
相关标签/搜索