Overview

  • Apache ZooKeeper is an effort to develop and maintain an open-source server which enables highly reliable distributed coordination.
  • zookeeper: Because coordinating distributed systems is a Zoo. 叫Zookeeper的原因是,协调分布式系统就好像管理动物园一样233

What is Zookeeper?

  • A centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services.
  • Zookeeper是一个为分布式应用而生的高性能协调服务。它以非常简单的接口提供了常见服务:包括命名、配置管理、同步和组服务。
  • 可以使用Zookeeper来实现consensus, group management, leader election, and persence protocols.
  • 协调服务很容易出现错误,比如race conditions(竞态条件) and deadlock. 因为Zookeeper的motivation就是减轻分布式系统实现协调系统的负担。

Why Zookeeper?

  • 在Zookeeper之前我们需要理解分布式协调技术。
  • 分布式协调技术:用以解决分布式环境中多个进程之间的同步控制,让它们有序地去访问某种临界资源,防止造成“脏数据”。
  • 为什么“分布式”协调技术与单机不同(或者说比单机难):根本原因就在于网络是不可靠的
  • 网络不可靠:存在这种可能--你对一个服务的调用失败并不一定真的是执行失败,也可能是网络故障,比如响应返回失败。
  • 最初,Zookeeper就是分布式锁的实现,在某种程序上是Chubby的开源版本。
  • 后来,Zookeeper在分布式锁的基础上,实现了配置维护、组服务、分布式消息队列、分布式通知/协调等。

从一个例子理解

  • 一个最典型的例子是基于单点故障的master选举

传统的热备方案:

  • 热备节点定期给主节点发ping包,如果未收到master的ack,则认为master挂了。热备便会接替原master称为master。但是如果ack只是因为网络故障,也就是原master实际上还活着,那么就会出问题--网络存在双master。

Zookeeper的解决方案

  • master启动时会向Zookeeper注册一个节点。【注册的节点在zk的术语里被称为znode。zk的数据模型是一个层级的命名空间,存储在内存中,以获取高吞吐量和低延迟。】
  • 当masterA挂了之后,Zookeeper会自动感知节点的变化,然后再次选举masterB
  • 当masterA恢复之后,会再次向Zookeeper注册一个节点,此时它注册的节点会是“master-00003",Zookeeper会感知节点变化再次发动选举,这是masterB会再次获胜继续担任master。(Zookeeper会严格按编号选举小的。注册的时候也维持一个number顺序。)
  • 在这样的设计中,不管masterA是否真的挂掉(就算Zookeeper没收到masterA的ack仅仅是因为网络原因,此时Zookeeper仍然将masterA当做挂掉了),Zookeeper会删除A而选举B。若masterA没挂,之后会再注册A,这样不会出现双master。

Design

  • Zookeeper is simple:
    • ZooKeeper allows distributed processes to coordinate with each other through a shared hierarchal namespace which is organized similarly to a standard file system. 关于hierarchal namespace等等相关的可以往下看。
  • Zookeeper is replicated:
    • The servers that make up the zookeeper service must all know about each other. Zookeeper服务中的servers都必须知道彼此。
    • They maintain in-memory image of state, along with a transaction logs and snapshots in a persistent store.
    • 只要多数servers是可用的,Zookeeper服务就是可用的。
    • clients连接到一个单一的Zookeeper server,client维持一个TCP连接,以发送请求,获取答复,获取watch events,发送心跳。如果TCP连接中断,client将会连接到另一个server。
  • Zookeeper is ordered:
    • ZooKeeper stamps each update with a number that reflects the order of all ZooKeeper transactions. Subsequent operations can use the order to implement higher-level abstractions, such as synchronization primitives. Zookeeper的时间戳通过一个数字更新,该数字反映了所有Zookeeper事务的顺序。随后的操作可以使用该顺序来实现高层抽象,比如同步原语。
  • Zookeeper is fast:
    • It is especially fast in "read-dominant" workloads.
    • ZooKeeper applications run on thousands of machines, and it performs best where reads are more common than writes, at ratios of around 10:1.

Data Model

NameSpace

  • The name space provided by ZooKeeper is much like that of a standard file system.
  • A name is a sequence of path elements separated by a slash (/). Every node in ZooKeeper's name space is identified by a path.

Nodes and ephemeral nodes

  • 不同于标准文件系统,zk中的每个节点可以有数据,也可以有children(相当于一个节点既可以是目录,同时还是文件)。
  • zk被设计用于存储coordination data:status information, configuration, location information, etc. 因此,每个节点存储的数据非常小,kb级别。
  • Znodes维持一个stat structure,其中包括数据变换,ACL(访问控制列表)变换和时间戳的版本号,以允许缓存验证和协调更新。每次znode数据变换,版本号都会增加。
  • ZooKeeper also has the notion of ephemeral nodes. These znodes exists as long as the session that created the znode is active. When the session ends the znode is deleted. Ephemeral nodes are useful when you want to implement [tbd]. 短暂节点:这种节点只有在创建该节点的session active的时候存在。

Summary

  • zk作为一个分布式的服务框架,主要用来解决分布式集群中的应用系统一致性问题。它能提供类似于文件系统的目录节点树的数据存储。但是要知道,zk并不是专门用来存储数据的,它的主要作用是维护和监控你存储的数据的状态变化,从而达到数据的集群管理
  • zk所存储的数据是有限制的:
    • 数据大小:zk的数据存储在一个叫ReplicatedDataBase的数据库中,这是一个内存数据库。zk主要是协调功能,并不是用来存储数据的。
    • 数据类型:要根据所需功能来选择相应的数据。zk所实现的功能都是由znode节点的性质及其所关联的数据决定的。例如:
      • 集群管理:利用临时节点特性,节点关联的是机器的主机名、IP地址等相关信息。集群的单点故障也属于该范畴。
      • 统一命名:主要利用节点的唯一性和目录节点树结构。
      • 配置管理:节点关联的是配置信息。
      • 分布式锁:节点关联的是要竞争的资源。

ZK应用场景

  • zk是一个高可用的分布式数据管理与系统协调框架。zk可应用于多种场景。
  • zk实现的任何功能都离不开zk的数据结构,任何功能都是利用”Znode结构特性 + 节点关联的数据”来实现的。
  • 下面仅讨论集群管理功能

Cluster Management

典型场景

  • 集群机器监控:要求能够快速对集群中机器变化做出响应。
    • 传统做法:利用一个监控系统,实时检测机器机器是否alive。该监控系统提供某种手段(比如ping)定时监测每个机器,或者每个机器定时向监控系统汇报"I am alive"。这种做法存在的问题包括:1)集群中机器有变动时,牵连修改的东西较多;2)有一定的时延。
    • 利用zk:实施另一种集群机器存活监控系统,通过1)客户端在节点x上注册一个watcher,如果x的子节点变化了,会通知该client;2)创建EPHEMERAL类型的节点,一旦client和server的session过期,那么该节点就会消失。
      • 如下:
      • 如上,我们在zk上有一个znode叫/configuration,那么集群中每一个机器启动时都会去该znode下创建一个EPHEMERAL类型节点,比如server1创建/Configuration /Server1,server2创建/Configuration /Server1,然后Server1和Server2都watch /Configuration 这个父节点,那么也就是这个父节点下数据或者子节点变化都会通知对该节点进行watch的客户端。因为EPHEMERAL类型节点有一个很重要的特性,就是客户端和服务器端连接断掉或者session过期就会使节点消失,那么在某一个机器挂掉或者断链的时候,其对应的节点就会消失,然后集群中所有对/Configuration进行watch的客户端都会收到通知,然后取得最新列表即可。
  • master选举:
    • zk:
      • 1)利用zk的强一致性,能保证在分布式高并发情况下节点创建的全局唯一性。即:同时有多个客户端请求创建Master节点,最终一定只有一个客户端请求能够创建成功。利用这个特性,就能很轻易的在分布式环境中进行集群选举了。
      • 2)动态master选举:利用EPHEMERAL_SEQUENTIAL类型节点的特性了,这样每个节点会自动被编号。允许所有请求都能够创建成功,但是得有个创建顺序,每次选取序列号最小的那个机器作为Master 。

一个🌰

假设我们的集群有:

(1) 20个搜索引擎的服务器:每个负责总索引中的一部分的搜索任务。

  ① 搜索引擎的服务器中的15个服务器现在提供搜索服务。

  ② 5个服务器正在生成索引。

  这20个搜索引擎的服务器,经常要让正在提供搜索服务的服务器停止提供服务开始生成索引,或生成索引的服务器已经把索引生成完成可以搜索提供服务了。

(2) 一个总服务器:负责向这20个搜索引擎的服务器发出搜索请求并合并结果集。

(3) 一个备用的总服务器:负责当总服务器宕机时替换总服务器。

(4) 一个web的cgi:向总服务器发出搜索请求。

使用Zookeeper可以保证:

(1) 总服务器:自动感知有多少提供搜索引擎的服务器,并向这些服务器发出搜索请求。

(2) 备用的总服务器:宕机时自动启用备用的总服务器。

(3) web的cgi:能够自动地获知总服务器的网络地址变化。

(4) 实现如下:

  ① 提供搜索引擎的服务器都在Zookeeper中创建znode,zk.create("/search/nodes/node1""hostname".getBytes()Ids.OPEN_ACL_UNSAFE,CreateFlags.EPHEMERAL);

  ② 总服务器可以从Zookeeper中获取一个znode的子节点的列表,zk.getChildren("/search/nodes", true);

  ③ 总服务器遍历这些子节点,并获取子节点的数据生成提供搜索引擎的服务器列表;

  ④ 当总服务器接收到子节点改变的事件信息,重新返回第二步;

  ⑤ 总服务器在Zookeeper中创建节点,zk.create("/search/master", "hostname".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateFlags.EPHEMERAL);

  ⑥ 备用的总服务器监控Zookeeper中的"/search/master"节点。当这个znode的节点数据改变时,把自己启动变成总服务器,并把自己的网络地址数据放进这个节点。

  ⑦ web的cgi从Zookeeper中"/search/master"节点获取总服务器的网络地址数据,并向其发送搜索请求。

  ⑧ web的cgi监控Zookeeper中的"/search/master"节点,当这个znode的节点数据改变时,从这个节点获取总服务器的网络地址数据,并改变当前的总服务器的网络地址。

FYI