当设计一个分布式系统或微服务架构系统时,通常须要设计和开发一些协调服务。Apache ZooKeeper是一个分布式、开源的分布式应用协调服务,也可理解成一个为分布式应用提供一致性服务的应用程序,主要做用可简化分布式系统搭建及缩短开发周期。ZooKeeper是目前经常使用的开源解决方案之一。html
本文主要针对ZooKeeper的安装部署、应用场景、开发对接API等,做简单入门级整理介绍,方便开发人员后续深刻研究。node
ZooKeeper 做为一个分布式的服务框架,主要用来解决分布式集群中应用系统的一致性问题。提供基于相似于文件系统的目录节点树方式的数据存储,ZooKeeper的做用主要是用来维护和监控存储的数据的状态变化。经过监控这些数据状态的变化,从而能够达到基于数据的集群管理。git
ZooKeeper 虽然是一个针对分布式系统的协调服务,但它自己也是一个分布式应用程序。ZooKeeper 遵循一个简单的客户端-服务器模型。github
▲ ZooKeeper 的客户端-服务器架构apache
ZooKeeper 有一个相似于文件系统的数据模型,由 znodes 组成。设计模式
每一个 ZooKeeper 服务器还在磁盘上维护了一个事务日志,记录全部的写入请求。服务器
在启动 ZooKeeper 服务时,集合体中的某个节点被选举为领导者;节点数量应该是奇数。session
Zookeeper 从设计模式角度来看,是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理分布式应用系统关心的数据,而后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper 就将负责通知已经注册的那些观察者作出相应的反应,从而实现集群中相似 Master/Slave 管理模式。架构
ZooKeeper 是一个面向分布式系统的构建模块,下面是当设计一个分布式系统时,典型的业务应用场景。框架
命名服务是将一个名称映射到与该命名有关联的一些信息的服务。Name Service 已是 Zookeeper 内置的功能,只要调用 Zookeeper 的 API 就能实现。如调用 create 接口就能够很容易建立一个目录节点。
配置的管理在分布式应用环境中很常见,可使用 ZooKeeper 集中存储和管理分布式系统的配置。同时还容许经过其中一个 ZooKeeper 客户端更改集中式配置,集中地更改分布式系统的状态。
Zookeeper 可以很容易的实现集群管理的功能,若有多台 Server 组成一个服务集群,那么必需要一个“领导者”知道当前集群中每台机器的服务状态,一旦有机器不能提供服务,集群中其它集群必须知道,从而作出调整从新分配服务策略。
为了容许在分布式系统中对共享资源进行有序的访问,可能须要实现分布式互斥。ZooKeeper 提供一种简单的方式来实现它们。
针对同步访问共享资源的需求,不管是实现一个生产者-消费者队列,仍是实现一个障碍,ZooKeeper 都提供一个简单的接口来实现该操做。Zookeeper 能够处理两种类型的队列:
当一个队列的成员都聚齐时,这个队列才可用,不然一直等待全部成员到达,这种是同步队列。
队列按照 FIFO 方式进行入队和出队操做,例如实现生产者和消费者模型。
ZooKeeper能够运行在多种系统平台上面,如下是支持的系统平台以及在该平台上是否支持开发环境或者生产环境。
在部署ZooKeeper的机器上须要安装Java运行环境。为了正常运行ZooKeeper,咱们须要JRE1.6或者以上的版本。
对于集群模式下的ZooKeeper部署,3个ZooKeeper服务进程是建议的最小进程数量,并且不一样的服务进程建议部署在不一样的物理机器上面,以减小机器宕机带来的风险,以实现ZooKeeper集群的高可用。
ZooKeeper下载地址
下载并解压ZooKeeper软件压缩包后,能够看到ZooKeeper包含如下的文件和目录:
bin目录:
ZooKeeper的可执行脚本目录,包括ZooKeeper服务进程,zk客户端,等脚本。
conf目录:
配置文件目录。zoo_sample.cfg为样例配置文件,须要修改成本身的名称,通常为zoo.cfg。log4j.properties为日志配置文件。
lib :
ZooKeeper依赖的包。
contrib目录:
一些用于操做ZooKeeper的工具包。
recipes目录:
ZooKeeper某些用法的代码示例。
单机模式的zk进程虽然便于开发与测试,但并不适合在生产环境使用。在生产环境下,咱们须要使用集群模式来对ZooKeeper进行部署。
注意!!!
在集群模式下,建议至少部署3个zk进程,或者部署奇数个ZooKeeper进程。若是只部署2个ZooKeeper进程,当其中一个ZooKeeper进程挂掉后,剩下的一个进程并不能构成一个Quorum的大多数。所以,部署2个进程甚至比单机模式更不可靠,由于2个进程其中一个不可用的可能性比一个进程不可用的可能性还大。
运行配置
在集群模式下,全部的ZooKeeper进程可使用相同的配置文件(指各个ZooKeeper进程部署在不一样的机器上面),例如如下配置:
tickTime=2000
dataDir=/home/myname/zookeeper
clientPort=2181
initLimit=5
syncLimit=2
server.1=192.168.229.160:2888:3888
server.2=192.168.229.161:2888:3888
server.3=192.168.229.162:2888:3888
initLimit :
ZooKeeper集群模式下包含多个zk进程,其中一个进程为leader,余下的进程为follower。initLimit配置follower与leader之间创建链接后进行同步的最长时间。
syncLimit :
配置follower和leader之间发送消息,请求和应答的最大时间长度。
tickTime :
tickTime则是上述两个超时配置的基本单位。
server.id=host:port1:port2:
其中id为一个数字,表示zk进程的id,这个id也是dataDir目录下myid文件的内容。host是该ZooKeeper进程所在的IP地址,port1表示follower和leader交换消息所使用的端口,port2表示选举leader所使用的端口。
注意!!!
若是仅为了测试部署集群模式而在同一台机器上部署ZooKeeper进程,server.id=host:port1:port2配置中的port参数必须不一样。可是,为了减小机器宕机的风险,强烈建议在部署集群模式时,将ZooKeeper进程部署不一样的物理机器上面。
启动
假如咱们打算在三台不一样的机器 192.168.229.160,192.168.229.161,192.168.229.162上各部署一个ZooKeeper进程,以构成一个ZooKeeper集群。三个ZooKeeper进程均使用相同的 zoo.cfg 配置:
tickTime=2000
dataDir=/home/myname/zookeeper
clientPort=2181
initLimit=5
syncLimit=2
server.1=192.168.229.160:2888:3888
server.2=192.168.229.161:2888:3888
server.3=192.168.229.162:2888:3888
在三台机器dataDir目录( /home/myname/zookeeper 目录)下,分别生成一个myid文件,其内容分别为1,2,3。而后分别在这三台机器上启动ZooKeeper进程,这样咱们便将ZooKeeper集群启动了起来。
链接
可使用如下命令来链接一个ZooKeeper集群:
bin/zkCli.sh -server 192.168.229.160:2181,192.168.229.161:2181,192.168.229.162:2181
客户端(以Java为例)要链接 Zookeeper 服务器能够经过建立 org.apache.zookeeper.ZooKeeper 的一个实例对象,而后调用这个类提供的接口来和服务器交互。接口以下所示:
String create(String path, byte[] data, List<ACL> acl,CreateMode createMode)
建立一个给定目录节点 path, 并给它设置数据,CreateMode 标识有四种形式的目录节点,分别是:
PERSISTENT:持久化目录节点,这个目录节点存储的数据不会丢失。
PERSISTENT_SEQUENTIAL:顺序自动编号的目录节点,这种目录节点会根据当前已存在的节点数自动加 1,而后返回给客户端已经成功建立的目录节点名。
EPHEMERAL:临时目录节点,一旦建立这个节点的客户端与服务器端口也就是 session 超时,这种节点会被自动删除。
EPHEMERAL_SEQUENTIAL:临时自动编号节点。
Stat exists(String path, boolean watch)
判断某个 path 是否存在,并设置是否监控这个目录节点,这里的 watcher 是在建立 ZooKeeper 实例时指定的 watcher,exists方法还有一个重载方法,能够指定特定的watcher。
Stat exists(String path,Watcher watcher)
重载方法,这里给某个目录节点设置特定的 watcher,Watcher 在 ZooKeeper 是一个核心功能,Watcher 能够监控目录节点的数据变化以及子目录的变化,一旦这些状态发生变化,服务器就会通知全部设置在这个目录节点上的 Watcher,从而每一个客户端都很快知道它所关注的目录节点的状态发生变化,而作出相应的反应。
void delete(String path, int version)
删除 path 对应的目录节点,version 为 -1 能够匹配任何版本,也就删除了这个目录节点全部数据。
List<String>getChildren(String path, boolean watch)
获取指定 path 下的全部子目录节点,一样 getChildren方法也有一个重载方法能够设置特定的 watcher 监控子节点的状态。
Stat setData(String path, byte[] data, int version)
给 path 设置数据,能够指定这个数据的版本号,若是 version 为 -1 怎么能够匹配任何版本。
byte[] getData(String path, boolean watch, Stat stat)
获取这个 path 对应的目录节点存储的数据,数据的版本等信息能够经过 stat 来指定,同时还能够设置是否监控这个目录节点数据的状态。
voidaddAuthInfo(String scheme, byte[] auth)
客户端将本身的受权信息提交给服务器,服务器将根据这个受权信息验证客户端的访问权限。
Stat setACL(String path,List<ACL> acl, int version)
给某个目录节点从新设置访问权限,须要注意的是 Zookeeper 中的目录节点权限不具备传递性,父目录节点的权限不能传递给子目录节点。目录节点 ACL 由两部分组成:perms 和 id。
perms:有 ALL、READ、WRITE、CREATE、DELETE、ADMIN 几种 。
id : 标识了访问目录节点的身份列表,默认状况下有如下两种:
ANYONE_ID_UNSAFE = new Id("world", "anyone")
AUTH_IDS = new Id("auth", "")
分别表示任何人均可以访问和建立者拥有访问权限。
List<ACL>getACL(String path,Stat stat)
获取某个目录节点的访问权限列表
除了以上这些上表中列出的方法以外还有一些重载方法,如都提供了一个回调类的重载方法以及能够设置特定 Watcher 的重载方法,具体的方法能够参考官方org.apache.zookeeper.ZooKeeper 类的 API 说明。
下面给出基本的操做 ZooKeeper 的示例代码,这样你就能对 ZooKeeper 有直观的认识了。下面的清单包括了建立与 ZooKeeper 服务器的链接以及最基本的数据操做:
ZooKeeper 基本的操做示例
与ZooKeeper集群的链接
建议用开源的zkClient简化代码。
官方地址
本文主要针对ZooKeeper的一些使用、应用场景、安装部署过程要点、开发对接API等进行简单入门级介绍,做为开发人员入门了解。后续如需详细了解ZooKeeper部署、开发、命令等请在官网参考官方文档资料等。
参考资料:Apache ZooKeeper官方文档及相关网上资料。
做者:陈楚相