当设计一个分布式系统或微服务架构系统时,一般需要设计和开发一些协调服务。Apache ZooKeeper是一个分布式、开源的分布式应用协调服务,也可理解成一个为分布式应用提供一致性服务的应用程序,主要作用可简化分布式系统搭建及缩短开发周期。ZooKeeper是目前常用的开源解决方案之一。
本文主要针对ZooKeeper的安装部署、应用场景、开发对接API等,作简单入门级整理介绍,方便开发人员后续深入研究。
ZooKeeper是什么?
ZooKeeper 作为一个分布式的服务框架,主要用来解决分布式集群中应用系统的一致性问题。提供基于类似于文件系统的目录节点树方式的数据存储,ZooKeeper的作用主要是用来维护和监控存储的数据的状态变化。通过监控这些数据状态的变化,从而可以达到基于数据的集群管理。
- ZooKeeper 虽然是一个针对分布式系统的协调服务,但它本身也是一个分布式应用程序。ZooKeeper 遵循一个简单的客户端-服务器模型。
▲ ZooKeeper 的客户端-服务器架构
- ZooKeeper 有一个类似于文件系统的数据模型,由 znodes 组成。
- 每个 ZooKeeper 服务器还在磁盘上维护了一个事务日志,记录所有的写入请求。
- 在启动 ZooKeeper 服务时,集合体中的某个节点被选举为领导者;节点数量应该是奇数。
Zookeeper 从设计模式角度来看,是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理分布式应用系统关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper 就将负责通知已经注册的那些观察者做出相应的反应,从而实现集群中类似 Master/Slave 管理模式。
常见应用场景
ZooKeeper 是一个面向分布式系统的构建模块,下面是当设计一个分布式系统时,典型的业务应用场景。
01 统一命名服务(Name Service)
命名服务是将一个名称映射到与该命名有关联的一些信息的服务。Name Service 已经是 Zookeeper 内置的功能,只要调用 Zookeeper 的 API 就能实现。如调用 create 接口就可以很容易创建一个目录节点。
02 配置管理(Configuration Management)
配置的管理在分布式应用环境中很常见,可以使用 ZooKeeper 集中存储和管理分布式系统的配置。同时还允许通过其中一个 ZooKeeper 客户端更改集中式配置,集中地更改分布式系统的状态。
03 集群管理(Group Membership)
Zookeeper 能够很容易的实现集群管理的功能,如有多台 Server 组成一个服务集群,那么必须要一个“领导者”知道当前集群中每台机器的服务状态,一旦有机器不能提供服务,集群中其它集群必须知道,从而做出调整重新分配服务策略。
04 共享锁(Locks)
为了允许在分布式系统中对共享资源进行有序的访问,可能需要实现分布式互斥。ZooKeeper 提供一种简单的方式来实现它们。
05 队列管理或同步
针对同步访问共享资源的需求,无论是实现一个生产者-消费者队列,还是实现一个障碍,ZooKeeper 都提供一个简单的接口来实现该操作。Zookeeper 可以处理两种类型的队列:
- 当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达,这种是同步队列。
- 队列按照 FIFO 方式进行入队和出队操作,例如实现生产者和消费者模型。
安装配置
01 前提条件
ZooKeeper可以运行在多种系统平台上面,以下是支持的系统平台以及在该平台上是否支持开发环境或者生产环境。
- 在部署ZooKeeper的机器上需要安装Java运行环境。为了正常运行ZooKeeper,我们需要JRE1.6或者以上的版本。
- 对于集群模式下的ZooKeeper部署,3个ZooKeeper服务进程是建议的最小进程数量,而且不同的服务进程建议部署在不同的物理机器上面,以减少机器宕机带来的风险,以实现ZooKeeper集群的高可用。
02 安装包说明
ZooKeeper下载地址
下载并解压ZooKeeper软件压缩包后,可以看到ZooKeeper包含以下的文件和目录:
bin目录:
ZooKeeper的可执行脚本目录,包括ZooKeeper服务进程,zk客户端,等脚本。
conf目录:
配置文件目录。zoo_sample.cfg为样例配置文件,需要修改为自己的名称,一般为zoo.cfg。log4j.properties为日志配置文件。
lib :
ZooKeeper依赖的包。
contrib目录:
一些用于操作ZooKeeper的工具包。
recipes目录:
ZooKeeper某些用法的代码示例。
03 集群模式
单机模式的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
对接API说明
客户端(以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 说明。
Java对接ZooKeeper样例
下面给出基本的操作 ZooKeeper 的示例代码,这样你就能对 ZooKeeper 有直观的认识了。下面的清单包括了创建与 ZooKeeper 服务器的连接以及最基本的数据操作:
ZooKeeper 基本的操作示例
与ZooKeeper集群的连接
建议用开源的zkClient简化代码。
官方地址
总结
本文主要针对ZooKeeper的一些使用、应用场景、安装部署过程要点、开发对接API等进行简单入门级介绍,作为开发人员入门了解。后续如需详细了解ZooKeeper部署、开发、命令等请在官网参考官方文档资料等。
参考资料:Apache ZooKeeper官方文档及相关网上资料。
作者:陈楚相
其他优质文章
来源:oschina
链接:https://my.oschina.net/u/4026796/blog/3166145