Zookeeper 笔记

尚硅谷入门永远的神

概念

基于观察者模式设计的分布式服务管理框架,负责存储和管理大家都关心的数据,接受观察者的注册,并在数据变更时通知注册的观察者们做出相应行动。【文件系统 + 通知机制】

特点

  1. 一个领导者 (Leader),多个跟随者 (Follower)组成的集群
  2. 半数以上节点存活就能正常服务,适合奇数台服务
  3. 全局数据一致
  4. 有序执行,来自同一个 Client 的更新请求按其发送顺序依次执行
  5. 数据更新原子性
  6. 实时性,同步速度块

数据结构

数据模型整体为一棵树。节点为 ZNode,默认能存储 1MB 的数据,通过其路径位移标识。

应用场景

  1. 统一命名服务
  2. 统一配置管理
    1. 集群配置一致
    2. 配置修改同步
  3. 统一集群管理
    1. 监控节点状态(监测其他节点)
    2. 同步节点状态(被其他节点监测)
  4. 服务器动态上下线
  5. 软负载均衡

参数配置

tickTime-----------通信心跳时间/ms
initLimit----------Leader-Follower初始通信时限/s
syncLimit ---------Leader-Follower同步通信时限/s
dateDir------------Zookeeper数据保存路径
clientPort---------客户连接端口

集群

集群启动

  1. 安装文件路径下创建 zkData
  2. zkData 目录下创建 myid,并添加对应服务器编号(唯一)
  3. zoo.cfg 文件中增加集群配置 server.A = B : C : D
    1. A:数字,服务器编号
    2. B:服务器地址
    3. C:Leader-Follower 信息交换端口
    4. D:服务器选举端口

选举机制

初次选举

  1. 启动后投票自己
  2. 票数不满一半则保持 LOOKING 状态
  3. 交换选票,把票投给 myid 更大的服务器
  4. 票数满足则更改状态为 FOLLOWING / LEADING
  5. 已存在 Leader 后,新创建的服务会跟投 Leader,并修改状态

Client

  • SID:服务器ID,和 myid一致
  • ZXID:事务ID,标识一次服务器状态的变更
  • Epoch:每个 Leader 任期的代号。没有 Leader 使用逻辑时钟值

再次选举

Leader 选举条件:

  • 服务器启动时进入 Leader 选举
  • 服务器运行期间无法和 Leader 保持连接时进入选举

进入选举流程后,集群状态:

  • 集群中存在 Leader ==> 和 Leader 建立连接并同步
  • 集群中不存在 Leader ==> 进入 Leader 选举

选举关注 (Epoch, ZXID, SID) ,按照顺序对应值更大的服务器胜出。

批量操作脚本示例

#! /bin/bash
case $1 in
"start"){
    for i in 
    do
        ssh $i "/path/bin/zkServer.sh start"
    done
}
;;
"stop"){
    for i in 
    do
        ssh $i "/path/bin/zkServer.sh stop"
    done
}
;;
"status"){
    for i in 
    do
        ssh $i "/path/bin/zkServer.sh status"
    done
}
;;
esac

客户端

客户端命令操作

命令基本语法功能描述
help帮助
ls pathls 查看当前 znode 的子节点 [可监听]
-w 监听子节点变化
-s 附加次级信息
create普通创建
-s 含有序列
-e 临时(重启、超时消失)
get path获得节点的值
-w 监听节点内容变化
-s 附加次级信息
set设置节点具体值
stat查看节点状态
delete删除节点
deleteall递归删除节点

ZNode 节点数据信息

czxid --------- 创建节点的事务 id
ctime --------- znode 被创建的毫秒数(从 1970 年开始)
mzxid --------- znode 最后更新的事务 zxid
mtime --------- znode 最后修改的毫秒数(从 1970 年开始)
pZxid --------- znode 最后更新的子节点 zxid
cversion ------ znode 子节点变化号,znode 子节点修改次数
dataversion --- znode 数据变化号
aclVersion ---- znode 访问控制列表的变化号
ephemeralOwner  临时节点 -> znode 拥有者的 session id。非临时节点 -> 0
dataLength ---- znode 的数据长度
numChildren --- znode 子节点数量

ZNode 节点类型

  • 持久 Persistent:服务器和客户端断开连接后,创建的节点不删除
  • 短暂 Ephemeral:服务器和客户端断开连接后,创建的节点自删除
  • 持久化目录节点:客户端与 Zookeeper 断开连接后该节点依旧存在
  • 持久化顺序编号目录节点:带序号ZNode 名称后附加一个顺序标识,单调递增由父节点维护
  • 临时目录节点:客户端与 Zookeeper 断开连接后该节点被删除
  • 临时顺序编号目录节点:Zookeeper 给该节点名称进行顺序编号

监听器原理

  1. main() 线程
  2. main 中创建 Zk客户端,会产生两个新线程,负责监听和连接
  3. 通过 connect 将注册的监听事件发送给 Zookeeper
  4. 在 Zookeeper 的注册监听表中将注册的监听事件添加到列表中
  5. Zookeeper 监听到数据或路径变化,将信息发送给 Listener 线程
  6. Listener 线程内部调用处理方法
直接操作指令
get -w path ---------- 监听节点数据变化
ls -w path  ---------- 监听节点的子节点变化(注册一次生效一次)
// 客户端 API 操作示例
// ZooKeeper 构造方法
Zookeeper zkCli = new ZooKeeper(String connectString, int sessionTimeout, Watcher watcher);

// 创建节点
zkCli.create(String path, Byte[] data, List<ACL> acl, CreateMode createMode);

/**
 * 获取子节点并监听节点变化
 * @return List<String>
 */
zkCli.getChildren(String path, Watcher watcher);

/**
 * 判断节点是否存在
 * @return Stat
 */
zkCli.exist(String path, Watcher watcher);

客户端写数据流程

发送给 Leader 节点

发送给 Follower 节点