ZooKeeper是一个开源的 分布式协调服务 ,由雅虎创建,是Google Chubby的开源实现 。分布式应用程序可以基于ZooKeeper实现诸如 数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列 等功能。
简介ZooKeeper是一个开源的 分布式协调服务 ,由雅虎创建,是Google Chubby的开源实现 。分布式应用程序可以基于ZooKeeper实现诸如 数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列 等功能。
基本概念本节将介绍ZooKeeper的几个核心概念。这些概念贯穿于之后对ZooKeeper更深入的讲解,因此有必要预先了解这些概念。
集群角色在ZooKeeper中,有三种角色:
Leader
Follower
Observer
一个ZooKeeper集群同一时刻只会有一个Leader,其他都是Follower或Observer。
ZooKeeper配置很简单,每个节点的配置文件(zoo.cfg)都是一样的,只有myid文件不一样。myid的值必须是zoo.cfg中server.{数值}的{数值}部分。
zoo.cfg文件内容示例:
maxClientCnxns=0 # The number of milliseconds of each tick tickTime=2000 # The number of ticks that the initial # synchronization phase can take initLimit=10 # The number of ticks that can pass between # sending a request and getting an acknowledgement syncLimit=5 # the directory where the snapshot is stored. dataDir=/var/lib/zookeeper/data # the port at which the clients will connect clientPort=2181 # the directory where the transaction logs are stored. dataLogDir=/var/lib/zookeeper/logs server.1=192.168.20.101:2888:3888 server.2=192.168.20.102:2888:3888 server.3=192.168.20.103:2888:3888 server.4=192.168.20.104:2888:3888 server.5=192.168.20.105:2888:3888 minSessionTimeout=4000 maxSessionTimeout=100000在装有ZooKeeper的机器的终端执行 zookeeper-server status 可以看当前节点的ZooKeeper是什么角色(Leader or Follower)。
[root@node-20-103 ~]# zookeeper-server status JMX enabled by default Using config: /etc/zookeeper/conf/zoo.cfg Mode: follower [root@node-20-104 ~]# zookeeper-server status JMX enabled by default Using config: /etc/zookeeper/conf/zoo.cfg Mode: leader如上,node-20-104是Leader,node-20-103是follower。
ZooKeeper默认只有Leader和Follower两种角色,没有Observer角色。
为了使用Observer模式,在任何想变成Observer的节点的配置文件中加入: peerType=observer 并在所有server的配置文件中,配置成observer模式的server的那行配置追加:observer,例如: server.1:localhost:2888:3888:observer
ZooKeeper集群的所有机器通过一个 Leader选举过程 来选定一台被称为 『Leader』 的机器, Leader服务器 为客户端提供 读 和 写 服务。
Follower和Observer都 能 提供 读 服务, 不能 提供 写 服务。两者唯一的区别在于, Observer 机器 不参与Leader选举 过程,也 不参与写操作 的『过半写成功』策略,因此Observer可以在 不影响写性能 的情况下 提升 集群的 读性能 。
会话(Session)Session是指 客户端会话 ,在讲解客户端会话之前,我们先来了解下 客户端连接 。在ZooKeeper中,一个客户端连接是指客户端和ZooKeeper服务器之间的 TCP长连接 。ZooKeeper对外的服务端口默认是 2181 ,客户端启动时,首先会与服务器建立一个TCP连接,从第一次连接建立开始,客户端会话的生命周期也开始了,通过这个连接,客户端能够通过 心跳检测 和服务器保持有效的会话,也能够向ZooKeeper服务器 发送请求 并 接受响应 ,同时还能通过该连接接收来自服务器的 Watch事件通知 。Session的 SessionTimeout 值用来设置一个客户端会话的 超时时间 。当由于服务器压力太大、网络故障或是客户端主动断开连接等各种原因导致客户端连接断开时,只要在SessionTimeout规定的时间内能够 重新连接上 集群中 任意一台 服务器,那么之前创建的会话 仍然有效 。
数据节点(ZNode)在谈到分布式的时候, 一般 『节点』指的是组成集群的每一台 机器 。而ZooKeeper中的数据节点是指 数据模型 中的 数据单元 ,称为 ZNode 。ZooKeeper将所有数据存储在 内存中 ,数据模型是一棵 树(ZNode Tree) ,由斜杠(/)进行分割的路径,就是一个ZNode,如/hbase/master,其中hbase和master 都是 ZNode。每个ZNode上都会保存 自己的数据内容 ,同时会保存一系列 属性信息 。
注: 这里的ZNode可以理解成 既是 Unix里的 文件 , 又是 Unix里的 目录 。因为每个ZNode不仅本身可以 写数据 (相当于Unix里的文件),还可以有 下一级文件或目录 (相当于Unix里的目录)。
在ZooKeeper中,ZNode可以分为 持久节点 和 临时节点 两类。
持久节点所谓持久节点是指一旦这个ZNode被创建了,除非主动进行ZNode的移除操作,否则这个ZNode将一直保存在ZooKeeper上。
临时节点临时节点的生命周期跟客户端会话绑定,一旦客户端会话失效,那么这个客户端创建的所有临时节点都会被移除。
另外,ZooKeeper还允许用户为每个节点添加一个特殊的属性:SEQUENTIAL。一旦节点被标记上这个属性,那么在这个节点被创建的时候,ZooKeeper就会自动在其节点后面追加上一个整型数字,这个整型数字是一个由父节点维护的自增数字。
版本ZooKeeper的每个ZNode上都会存储数据,对应于每个ZNode,ZooKeeper都会为其维护一个叫作Stat的数据结构,Stat中记录了这个ZNode的三个数据版本,分别是version(当前ZNode的版本)、cversion(当前ZNode子节点的版本)和aversion(当前ZNode的ACL版本)。
状态信息每个ZNode除了存储数据内容之外,还存储了ZNode本身的一些状态信息。用 get 命令可以同时获得某个ZNode的内容和状态信息。如下:
[zk: localhost:2181(CONNECTED) 23] get /yarn-leader-election/appcluster-yarn/ActiveBreadCrumb appcluster-yarnrm1 cZxid = 0x1b00133dc0 //Created ZXID,表示该ZNode被创建时的事务ID ctime = Tue Jan 03 15:44:42 CST 2017 //Created Time,表示该ZNode被创建的时间 mZxid = 0x1d00000063 //Modified ZXID,表示该ZNode最后一次被更新时的事务ID mtime = Fri Jan 06 08:44:25 CST 2017 //Modified Time,表示该节点最后一次被更新的时间 pZxid = 0x1b00133dc0 //表示该节点的子节点列表最后一次被修改时的事务ID。注意,只有子节点列表变更了才会变更pZxid,子节点内容变更不会影响pZxid。 cversion = 0 //子节点的版本号 dataVersion = 11 //数据节点的版本号 aclVersion = 0 //ACL版本号 ephemeralOwner = 0x0 //创建该节点的会话的seddionID。如果该节点是持久节点,那么这个属性值为0。 dataLength = 22 //数据内容的长度 numChildren = 0 //子节点的个数在ZooKeeper中,version属性是用来实现乐观锁机制中的『写入校验』的(保证分布式数据原子性操作)。
事务操作在ZooKeeper中,能改变ZooKeeper服务器状态的操作称为事务操作。一般包括数据节点创建与删除、数据内容更新和客户端会话创建与失效等操作。对应每一个事务请求,ZooKeeper都会为其分配一个全局唯一的事务ID,用ZXID表示,通常是一个64位的数字。每一个ZXID对应一次更新操作,从这些ZXID中可以间接地识别出ZooKeeper处理这些事务操作请求的全局顺序。
WatcherWatcher(事件监听器),是ZooKeeper中一个很重要的特性。ZooKeeper允许用户在指定节点上注册一些Watcher,并且在一些特定事件触发的时候,ZooKeeper服务端会将事件通知到感兴趣的客户端上去。该机制是ZooKeeper实现分布式协调服务的重要特性。
ACLZooKeeper采用ACL(Access Control Lists)策略来进行权限控制。ZooKeeper定义了如下5种权限。
CREATE: 创建子节点的权限。
READ: 获取节点数据和子节点列表的权限。
WRITE:更新节点数据的权限。
DELETE: 删除子节点的权限。
ADMIN: 设置节点ACL的权限。
注意:CREATE 和 DELETE 都是针对子节点的权限控制。
ZooKeeper典型应用场景ZooKeeper是一个 高可用 的分布式 数据管理与协调框架 。基于对ZAB算法的实现,该框架能够很好地保证分布式环境中数据的 一致性 。也是基于这样的特性,使得ZooKeeper成为了解决分布式一致性问题的利器。
数据发布与订阅(配置中心)数据发布与订阅,即所谓的 配置中心 ,顾名思义就是发布者将数据发布到ZooKeeper节点上,供订阅者进行数据订阅,进而达到 动态获取数据 的目的,实现配置信息的 集中式管理 和 动态更新 。
在我们平常的应用系统开发中,经常会碰到这样的需求:系统中需要使用一些通用的配置信息,例如 机器列表信息 、 数据库配置信息 等。这些全局配置信息通常具备以下3个特性。
数据量通常比较 小。
数据内容在运行时 动态变化 。
集群中各机器共享, 配置一致 。
对于这样的全局配置信息就可以发布到ZooKeeper上,让客户端(集群的机器)去订阅该消息。
发布/订阅系统一般有两种设计模式,分别是 推(Push) 和 拉(Pull) 模式。
推: 服务端主动 将数据更新发送给所有订阅的客户端。
拉: 客户端主动 发起请求来获取最新数据,通常客户端都采用 定时轮询 拉取的方式。
ZooKeeper采用的是 推拉相结合 的方式。如下:
客户端想服务端 注册 自己需要关注的节点,一旦该节点的数据发生 变更 ,那么服务端就会向相应的客户端发送Watcher事件 通知 ,客户端接收到这个消息通知后,需要 主动 到服务端 获取 最新的数据( 推拉结合 )。
命名服务(Naming Service) 命名服务也是分布式系统中比较常见的一类场景。在分布式系统中,通过使用命名服务,客户端应用能够根据指定 名字 来获取 资源或服务的地址,提供者等信息 。被命名的实体通常可以是 集群中的机器,提供的服务,远程对象等等 ――这些我们都可以统称他们为 名字(Name) 。其中较为常见的就是一些分布式服务框架(如RPC、RMI)中的服务地址列表。通过在ZooKeepr里创建