Zookeeper是Hadoop分布式调度服务,用来构建分布式应用系统。构建一个分布式应用是一个很复杂的事情,主要的原因是我们需要合理有效的处理分布式集群中的部分失败的问题。例如,集群中的节点在相互通信时,A节点向B节点发送消息。A节点如果想知道消息是否发送成功,只能由B节点告诉A节点。那么如果B节点关机或者由于其他的原因脱离集群网络,问题就出现了。A节点不断的向B发送消息,并且无法获得B的响应。B也没有办法通知A节点已经离线或者关机。集群中其他的节点完全不知道B发生了什么情况,还在不断的向B发送消息。这时,你的整个集群就发生了部分失败的故障。

Zookeeper不能让部分失败的问题彻底消失,但是它提供了一些工具能够让你的分布式应用安全合理的处理部分失败的问题。

Zookeeper基本

是什么

是一个基于观察者模式设计的分布式服务管理框架,他负责存储和管理大家都关心的数据,然后接受管擦者的注册,一旦这些数据的状态发生了变化,Zookeeper就将负责通知已经在Zookeeper上注册的观察者做出相应的反应。

特点是什么

  1. 集群中半数以上的机器存活,Zookeeper集群就可以正常服务。

  2. 集群数据保持一致,每一个Server保存一分相同的数据副本,Client无论连接那个Server,数据都是一致的。

Zookeeper的工作机制

Zookeeper.png

Zookeeper 特点

Zookeeper特点

  • Zookeeper: 一个领导者(Leader) , 多个追随者(Follower) 组成的集群;
  • 集群中只要有半数以上节点存活,Zookeeper 集群就能正常服务;
  • 全局数据一致,每个Server保存一份相同的数据副本,Client 无论连接到哪个 Server , 数据都是一致的。
  • 更新请求顺序进行,来自同一个Client 的更新请求按其发送顺序依次执行;
  • 数据更新原子性,一次数据更新要么成功,要么失败。
  • 实时性,在一定时间范围内,Client能读到最新的数据。

Zookeeper 的重要概念

  • Zookeeper 本身就是一个分布式程序(半数以上的节点存活,Zookeeper 就能正常服务)
  • 为了保证高可用,最好是以集群形态来部署 Zookeeper , 这样只要集群中大部分机器是可用的(能够容忍一定的机器故障),那么Zookeeper 本身任然是可用的。
  • Zookeeper 将数据保存在内存中,这也就保证了高吞吐量和低延迟(但是内存限制了能够存储的容量不太大,此限制也是保持 znode 中存储的数据量较小的进一步原因)。
  • Zookeeper 是高性能的。在 “读” 多于 “写” 的应用程序中尤其的 高性能。因为“写” 会导致所有的服务器间同步状态(“读” 多于 “写” 是协调服务的典型场景)。
  • Zookeeper 有临时节点的概念。当创建临时节点的客户端会话一直保持活动,瞬时节点就一直存在。而当会话终结时,瞬时节点被删除。持久节点是指一旦这个 ZNode 被创建,除非主动进行 ZNode 的移除操作,否则这个 ZNode 将一直保存在 Zookeeper 上。
  • Zookeeper 底层其实只提供了两个功能:① 管理(存储、读取)用户程序提交的数据; ② 为用户程序提交数据节点监听服务

Session (会话)

Session 是指 Zookeeper 服务器与客户端会话。在 Zookeeper 中,一个客户端连接是指客户端和服务器之间的 TCP 长连接。客户端启动的时候,首先会和服务器建立一个 TCP 连接,客户端能够通过 心跳 检测和服务保持有效的会话,也能够向 Zookeeper 服务器发送请求并接受响应,同时还能通过该链接接收来自服务器的 Watch 事件通知。

Session 的 sessionTimeout 值用来设置一个客户端会话的超时时间。当用于服务器压力太大、网络故障或是在客户端主动断开连接等各种原因导致客户端连接断开的时,只要在 sessionTimeout 规定的时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话依然有效。

在为客户端创建会话之前,服务端首先会为每个客户端都分配一个 sessionID , 由于 sessionID 是 Zookeeper 会话的一个重要标识,许多与会话相关的运行机制都是基于这个 sessionID 的(也就是,这个 sessionID 全局唯一) 。

Znode

在分布式中,所谓的节点是指集群中的每一台机器,称为机器节点。但是在 Zookeeper 中, 我们的节点有两种,一种是 机器节点 , 另一种就是 数据模型中的数据单元,也就是我们称为的数据节点——Znode 。

Zookeeper 将所有的数据存储在内存中,数据模型是一个 Znode Tree 。主节点是 / ,如下所示:
Znode

在节点中,我们又有持久节点和临时节点一说。所谓持久节点,除非你进行了ZNode的移除操作,否则 Zookeeper 将一直保留在 Zookeeper 上。临时节点不同的是,它的生命周期和当前会话一致。一旦会话结束,这个临时节点也就结束了。另外,Zookeeper 允许用户为每个节点添加一个特殊属性: SEQUENTIAL , 一旦节点被标记上这个属性,那么在节点被创建的时候,Zookeeper 会自动在其节点后面追加上一个整型数字,这个数字是一个由父节点维护的自增数字。

版本

每个 Znode 上都会存储数据,对应每个 ZNode , Zookeeper 会维护一个 Stat 的数据结构。 Stat 记录了这个 ZNode 的三个数据版本,分别是 version(当前的 ZNode 版本),cversion(当前 ZNode 子节点的版本), 和 cversion(当前 ZNode 的 ACL 版本)。

Watcher

Watcher(事件监听器), 是Zookeeper 中的一个很重要的特性。Zookeeper 允许用户在指定节点上注册一些 Watcher ,并且在一些特定事件触发的时候, Zookeeper 服务端 会将事件通知到感兴趣的客户端上去,该机制是 Zookeeper 实现分布式协调服务的重要特性。

ACL

Zookeeper 通过采用 ACL (aCCESSControlLists) 策略来进行权限控制。有如下五种权限:

  • create:创建子节点的权限
  • READ:获取节点数据和子节点列表的权限
  • WRITE:更新节点的权限
  • DELETE:删除节点的权限
  • ADMIN:设置节点ACL权限

Zookeeper 内部原理

选举机制

1)半数机制:集群中半数以上机器存活,集群可用。所以Zookeeper适合安装奇数台服务器。

2)Zookeeper虽然在配置文件中并没有指定Master和Slave。但是,Zookeeper工作时,是有一个节点为Leader,其他则为Follower,Leader是通过内部的选举机制临时产生的。

3)以一个简单的例子来说明整个选举的过程。

假设有五台服务器组成的Zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的。如图所示:
Zookeeper内部原理

(1)服务器1启动,此时只有它一台服务器启动了,它发出去的报文没有任何响应,所以它的选举状态一直是LOOKING状态。

(2)服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出,但是由于没有达到超过半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1、2还是继续保持LOOKING状态。

(3)服务器3启动,根据前面的理论分析,服务器3成为服务器1、2、3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的Leader。

(4)服务器4启动,根据前面的分析,理论上服务器4应该是服务器1、2、3、4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能接收当小弟的命了。

(5)服务器5启动,同4一样当小弟。

Stat 数据结构

1)czxid-创建节点的事务zxid

每次修改ZooKeeper状态都会收到一个zxid形式的时间戳,也就是ZooKeeper事务ID。

事务ID是ZooKeeper中所有修改总的次序。每个修改都有唯一的zxid,如果zxid1小于zxid2,那么zxid1在zxid2之前发生。

2)ctime - znode被创建的毫秒数(从1970年开始)

3)mzxid - znode最后更新的事务zxid

4)mtime - znode最后修改的毫秒数(从1970年开始)

5)pZxid-znode最后更新的子节点zxid

6)cversion - znode子节点变化号,znode子节点修改次数

7)dataversion - znode数据变化号

8)aclVersion - znode访问控制列表的变化号

9)ephemeralOwner- 如果是临时节点,这个是znode拥有者的session id。如果不是临时节点则是0。

10)dataLength- znode的数据长度

11)numChildren - znode子节点数量

监听器原理

  1. 首先要有一个 main() 线程;
  2. 在 main() 线程中创建 Zookeeper 客户端,这时就会创建两个线程,一个负责 网络连接通信(connet) , 一个负责监听(listener) .
  3. 通过 connet 线程将注册的监听事件发送给 Zookeeper.
  4. 在 Zookeeper 的注册监听器列表中将注册的监听事件添加到列表中 .
  5. Zookeeper 监听到有数据或路径变化,就会将这个消息发送到 listener 线程 .
  6. listener 线程内部调用了 process() 方法 .

Zookeeper的集群搭建

这是我的zookeeper的集群环境配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# The number of milliseconds of each tick
tickTime=30000
# 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.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/opt/module/zookeeper-3.4.10/dataDir
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
server.101=hadoop101:2888:3888
server.102=hadoop102:2888:3888
server.103=hadoop103:2888:3888

在我们的 /opt/module/zookeeper-3.4.10/dataDir中,我们需要添加 myid文件,且每个节点的myid内容必须保持不一致,如笔者的分别为:101,102,103.内容如下:

1
101

随后,我们便分发到各个机器上去。按要求修改相应的2内容。

Zookeeper的基本命令操作

我们看下Zookeeper的客户端操作:

1.进入客户端

1
bin/zkCli.sh

2.显示所有的操作命令

1
help

3.查看当前znode中包含的内容

1
ls /

4.查看当前znode中详细数据信息

1
ls2 /

5.分别创建2个普通节点

1
2
create /sanguo "jinlian"
create /sanguo/shuguo "liubei"

6.获得节点的值

1
get /sanguo

7.创建短暂节点

1
2
create -e /sanguo/wuguo "zhouyu"
# 仅在当前客户端下可以看到的目录,退出当前客户端或者使用第二客户端当前所创建的目录军备自动删除

8.创建带序号的节点

1
2
3
4
5
6
# 先创建一个普通的根节点
create /sanguo/weiguo "caocao"
# 开始创建一个带序号的节点
create -s /sanguo/weiguo/xiaoqiao "jinlian"
create -s /sanguo/weiguo/daqiao "jinlian"
create -s /sanguo/weiguo/diaocan "jinlian"

9.修改节点数据值

1
set /sanguo/weiguo "simayi"

10.节点的值变化监听

1
get /sanguo watch

11.节点的子节点变化监听(路径变化)

1
2
3
4
5
# 在hadoop104主机上注册监听/sanguo节点的子节点变化
ls /sanguo watch
# 在hadoop103主机/sanguo节点上创建子节点
create /sanguo/jin "simayi" Created /sanguo/jin
# 观察hadoop104主机收到子节点变化的监听

12.删除节点

1
delete /sanguo/jin

13.递归删除节点

1
rmr /sanguo/shuguo

14.查看节点状态

1
stat /sanguo

Zookeeper API

这部分内容,后续有时间在写,目前这个API用的比较少,至少我所在的公司不会有这个要求。读者也可以在网上搜索,会有一大堆的。