[22] Zookeeper-QuickStart
1. 概述
Zookeeper 是一个开源的分布式的、为分布式框架提供协调服务的 Apache 项目。
1.1 工作机制
Zookeeper 从设计模式角度来理解:
是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper 就将负责通知已经在 Zookeeper 上注册的那些观察者做出相应的反应。
【特点】
- Zookeeper 是由一个领导者(Leader),多个跟随者(Follower)组成的集群;
- 集群中只要有半数以上节点存活,Zk 集群就能正常服务。所以 Zk 适合安装奇数台服务器;
- 全局数据一致:每个 Server 保存一份相同的数据副本,Client 无论连接到哪个 Server,数据都是一致的;
- 更新请求顺序执行,来自同一个 Client 的更新请求按其发送顺序依次执行;
- 数据更新原子性,一次数据更新要么成功,要么失败;
- 实时性,在一定时间范围内,Client 能读到最新数据。
1.2 数据结构
ZooKeeper 数据模型的结构与 Unix 文件系统很类似,整体上可以看作是一棵树,每个节点称做一个 ZNode。每一个 ZNode 默认能够存储 1MB 的数据,每个 ZNode 都可以通过其路径唯一标识。
ZooKeeper 中的节点分为持久节点、持久顺序节点、临时节点、临时顺序节点。Dubbo 使用 ZooKeeper 作为注册中心时,不关心节点的创建顺序,只会创建持久节点和临时节点。
- 持久节点: 服务注册后保证节点不会丢失,注册中心重启也会存在;
- 临时节点: 服务注册后连接丢失或 session 超时,注册的节点会自动被移除。
1.3 应用场景
提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等。
a. 统一命名服务
在分布式环境下,经常需要对应用/服务进行统一命名,便于识别。例如:IP 不容易记住,而域名容易记住。
b. 统一配置管理
分布式环境下,配置文件同步非常常见:
- 一般要求一个集群中,所有节点的配置信息是一致的,比如 Kafka 集群;
- 对配置文件修改后,希望能够快速同步到各个节点上。
配置管理可交由 ZooKeeper 实现。
可将配置信息写入 ZooKeeper 上的一个 Znode,各个客户端服务器监听这个 Znode。一旦 Znode 中的数据被修改,ZooKeeper 将通知各个客户端服务器。
c. 统一集群管理
分布式环境中,实时掌握每个节点的状态是必要的。可根据节点实时状态做出一些调整。
ZooKeeper 可以实现实时监控节点状态变化
- 可将节点信息写入 ZooKeeper 上的一个 ZNode;
- 监听这个 ZNode 可获取它的实时状态变化。
d. 服务器节点动态上下线
e. 软负载均衡
在 Zookeeper 中记录每台服务器的访问数,让访问数最少的服务器去处理最新的客户端请求。
2. Watcher 机制
客户端和服务器维持数据交互通常有两种形式:
- 客户端定时向服务器轮询
- 服务器主动向客户端推送数据
ZooKeeper 采用的是方式2,主动向客户端推送数据。客户端注册监听它关心的节点(注册 Watcher 监听指定节点),当节点状态发生变化(数据变化、子节点增减变化)时,则相应的 Watcher 被触发,ZooKeeper 服务会通知客户端,这就是 Watcher 机制。
Watcher 有以下特点:
- 【主动推送】Watcher 被触发时,由 ZooKeeper 主动将更新推送给客户端,而不需要客户端轮询;
- 【一次性】在节点上注册 Watcher 监听后,当节点状态发生变化时该 Watcher 只会被触发一次,如果客户端想再收到后续发生变化的通知,需要重新再注册一次 Watcher;
- 【可见性】如果一个客户端在读请求中附带 Watcher,Watcher 被触发的同时再次读取数据,客户端在得到 Watcher 消息之前肯定不可能看到更新后的数据。换句话说,更新通知先于更新结果;
- 【顺序性】如果多个更新触发了多个 Watcher ,那 Watcher 被触发的顺序与更新顺序一致。
3. 会话机制
ZooKeeper 客户端通过〈TCP 长连接〉连接到 ZooKeeper 服务集群。会话 (Session) 从第一次连接开始就已经建立,之后通过心跳检测机制来保持有效的会话状态。
通过这个连接,客户端可以发送请求并接收响应,同时也可以接收到 Watch 事件的通知。一旦一台客户端与一台服务器建立连接,这台服务器会为这个客户端创建一个新的会话。
每个会话都会有一个超时时间。若由于服务器压力过大、网络故障等各种原因导致客户端连接断开时,只要在会话超时时间之内能够重新连接上 ZooKeeper 服务器,那么之前创建的会话仍然有效。若服务器在超时时间内没有收到任何请求,则相应会话被视为过期。一旦会话过期,就无法再重新打开,且任何与该会话相关的临时节点都会被删除。
通常来说,会话应该长期存在,而这需要由客户端来保证。客户端可以通过心跳方式来保持会话不过期。
4. Dubbo:服务注册中心*
当服务提供者启动时,服务提供者将自己提供的服务信息注册到注册中心,注册中心将这些信息记录下来。服务消费者启动时,向注册中心发起订阅,将自己感兴趣的服务提供者的信息拉取到本地并缓存起来,用于后续远程调用。另外,注册中心能够感知到服务提供者新增或者下线,并更新自己的服务信息,同时通知服务消费者告知服务提供者新增/下线,从而消费者也可以动态感知到服务提供者的变化。
如下图所示,服务提供者(集成了 Zk 客户端)在服务启动时,会通过 Zk 客户端与 Zk 服务端建立连接,将服务提供者信息(提供者的 IP 地址、端口、服务接口信息等)注册到 ZooKeeper 服务端,这时会在 ZooKeeper 服务端生成一个临时节点来存储这些服务信息,这就是服务提供者的注册操作。
服务消费者(集成了 Zk 客户端)在服务启动时,会通过 Zk 客户端与 Zk 服务端建立连接,拉取自己感兴趣的服务提供者信息并缓存到本地,同时也会对自己感兴趣的节点(比如服务提供节点)注册 Watcher 监听。后续发起远程调用时,会从本地缓存的服务提供者信息通过负载均衡等策略选择一台服务提供者发起服务调用。
如果服务提供者扩容新增了机器,服务提供者会向 Zk 发起新的注册操作,在对应的目录下创建临时节点(代表这台新增的服务提供者信息),同时会触发之前服务消费者注册的 Watcher 监听,ZooKeeper 服务端会将变更信息推送到服务消费,服务消费者在接收到变更后会更新自己本地的服务提供者信息,这样就完成了服务的自动扩容。
同样的,当某台服务提供者下线,它与 ZooKeeper 服务端的连接会断掉,因为服务注册时创建的是临时节点,因此当连接断掉后,该临时节点会被删除,同时会触发之前服务消费者注册的 Watcher 监听,相应的服务消费者会收到通知刷新自己本地的服务提供者信息缓存。
5. 本地安装
从 https://zookeeper.apache.org/ 中下载 3.5.7 版本。
- 安装 JDK
- 拷贝 apache-zookeeper-3.5.7-bin.tar.gz 安装包到 Linux 系统下;
- 配置修改
# 解压到指定目录后修改目录名,简化为 zookeeper-3.5.7 tar -zxvf apache-zookeeper-3.5.7-bin.tar.gz -C /opt/module/ # 将/opt/module/zookeeper-3.5.7/conf 下的 zoo_sample.cfg 修改为 zoo.cfg mv conf/zoo_sample.cfg conf/zoo.cfg # 打开 zoo.cfg 文件,修改 dataDir 路径 vim conf/zoo.cfg |———— dataDir=/opt/module/zookeeper-3.5.7/data
- 在 /opt/module/zookeeper-3.5.7/ 目录下创建 data 文件夹
- 启动 Zookeeper:
./bin/zkServer.sh start
- 查看进程是否启动:
jps -l
- 查看状态:
bin/zkServer.sh status
- 启动客户端:
bin/zkCli.sh
// 退出命令:quit
- 停止 Zookeeper:
./bin/zkServer.sh stop
6. 配置参数解读
Zookeeper 中的配置文件 zoo.cfg 中参数含义解读如下:
(1)tickTime
tickTime = 2000
通信心跳时间,Zookeeper 服务器与客户端心跳时间,单位 ms。
(2)initLimit
LF 初始通信时限,Leader 和 Follower 初始连接时能容忍的最多心跳数(tickTime 的数量)。
(3)syncLimit
LF 同步通信时限,Leader 和 Follower 之间通信时间如果超过 syncLimit * tickTime
,Leader 认为 Follwer 死掉,从服务器列表中删除 Follwer。
(4)dataDir
保存 Zookeeper 中的数据。注意:默认是 tmp 目录,容易被 Linux 系统定期删除,所以一般不用默认的 tmp 目录。
(5)clientPort
客户端连接端口,通常不做修改。