Fork me on GitHub

zk学习笔记

zk 学习笔记

一、参考资料:

zk,一般就是指 zookeeper。在 CAP 理论中,zk 主要保证 CA,并在发生网络分区错误时,仅提供只读能力。

学习书籍:《ZooKeeper 分布式过程协同技术详解》 Flavio Junqueira /Benjamin Reed

推荐阅读:Zookeeper你应该了解基础知识

二、核心内容:

2.1 主从模型

  1. 主从模型需要解决的三大问题:
    1. 主节点崩溃:
      1. 可以使用备份从节点,但如果想要恢复到原主节点崩溃时的状态,就要通过 zk 来获取此状态信息。
      2. 假崩溃:当主结点负载很高,导致的消息延迟时,备份主结点转正,此时系统就存在了两个主节点。
      3. 脑裂:主要指网络分区引起的、系统被分为子系统独立工作的情况。多个从节点因网络分区中断了跟主节点的通信,然后与第二主节点建立 master-slave 关系。脑裂是要被重点避免的情况。
    2. 从节点崩溃:
      1. 主结点需要检测① worker 是否崩溃;② 哪些 worker 存活以便接手崩溃 worker 的工作。
      2. 崩溃 worker 的任务执行进度如何,是否需要清除异常状态等。
    3. 通信故障:
      1. 跟任务的幂等性有关,如果任务是幂等的,在任务再分配时无需额外的动作。
      2. 但如果任务是非幂等的,任务再分配时,需要验证第一个 worker 是否已完成了工作,同时 app 需要考虑任务被多次重复执行的可能性。
  2. zk 为了配合主从模型,所以需要具备以下能力:
    1. 主节点选举;
    2. 崩溃检测;
    3. 成员关系管理;
    4. 元数据管理;

2.2 zk 的数据模型

采用树状模型(与文件系统很像,但有所不同,zk 使用 znode 的概念):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
root

|-- server id /master

|-- /workers

​ |-- /workers/worker-1 ## 保存某个可用 worker 结点的信息

​ |-- /workers/worker-2

|-- /tasks

​ |-- /tasks/task-1 ## 保存已被创建并等待执行的某个 task 信息(未分配)

​ |-- /tasks/task-2

|-- /assign

​ |-- /assign/worker-1

​ |-- /assign/worker-1/task-1-1 ## 保存从属于worker-1的 task 信息(已分配)

​ |-- /assign/worker-1/task-1-2

注:znode 中的数据以字节数组的形式存储(使用工具序列化后存入),但可以无数据。

2.3 对外 Api

1
2
3
4
5
6
create /path data   ##创建一个名为/path 的结点,并包含数据 data
delete /path ## 此操作发生前会校验 znode 的版本号
exists /path
setData /path data ## 此操作发生前会校验 znode 的版本号
getData /path
getChildren /path ##获取所有/path 结点的子节点列表

注:znode 的读写都是整个结点粒度的,不存在局部读写的情况。

注 2:版本是用来阻止并行操作的不一致性。

2.4 znode 的结点分类

  1. 一般 znode 分为持久结点临时结点两种:

    1. 持久结点:可以将一些数据落盘。虽然 zk 的数据一般都是在内存中,
    2. 临时结点:当 client 崩溃时,或者跟 zk 连接关闭时(client 与 zk 的 session 关闭时),临时结点会被删除,删除动作可主动可被动。临时结点如果拥有子节点,那么子节点也是临时结点。
    3. 有序结点:是另一个范畴的概念。持久结点和临时结点分别可以设置为有序的,创建有序结点时,命名会分配到唯一一个单调递增的整数序号。

2.5 notification 机制

  1. client 向 zk 注册需要接受通知的 znode,并对 znode 设置监视点(watch);
  2. 当 znode 发生变更时,client 会接收到通知,一次性的watch 发生失效,然后会继续设置下一个 watch;
    • 接到通知与下一个 watch 设完之间存在时间差,此时znode 可能发生再次变更。为了获取此变更,设下一个 watch 前,client 会再读一次 znode 的状态。

2.6 zk 的 server 模式

  1. 通常分为独立模式仲裁模式
    1. 用人话讲:就是单机模式和集群模式。
    2. [重点]仲裁模式下,所有 server 都维护相同的数据树,但 client 不可能等待所有 server 完全复制数据一致后才工作,所以引入了法定人数的折中选择。
  2. 法定人数:保证 zk 工作的 server 最小数量。(只有满足了人数,才能保证投票立法有效)。
    1. 举例:5 个 server 中,法定人数为 3 个,只有当至少 3 个 zkServer 保证client 的操作生效时,client 的工作才能继续下去。而且,剩下的 2 个 server 也会最终一致。
    2. 法定人数采用多数方案,而且总 server 数一般为奇数,偶数系统较脆弱。
      1. 偶数情况举例:如果总共 4 个 server,那么法定为 3 个,系统只能允许最多 1 台 server 崩溃。
      2. 奇数情况举例:如果总共 5 个 server,那么法定也为 3 个,系统可以允许最多2 台 server 崩溃,系统将更加牢靠。

2.7 client 与 zk 之间的 session

  1. client 与 zk 的某一个 server 之间建立 Tcp 连接。
    1. session具有透明性。如果连接不可用时,session 会被转移到另一个 server 上。
      1. 此时session不会过期,只是会经历 connected - connecting - connected 的状态转换过程。
      2. 欲建立连接的备胎 server需要保证状态最新(具有最新的事务标识符即 zkid),否则即使此 server 可用也将不会建立连接。
    2. session 保障顺序性,同一个 session 中的 request 以 FIFO 顺序执行。但跨 Session 时不保证顺序性。

2.8 多 server 间的通信

使用配置文件如下:

1
2
3
4
5
6
7
8
tickTime=2000
initLimit=10
syncLimit=5
dataDir=./data
clientPort=2181
server.1=127.0.0.1:2222:2223 ## 编号1【ip地址 :仲裁通信 port 号 :群首选举 port 号】
server.2=127.0.0.1:3333:3334 ## 编号 2 的 zkServer,其他类似
server.3=127.0.0.1:4444:4445 ## 编号 3 的 zkServer,其他类似

注:单机模拟时因为 ip 相同,所以选用不同的 port 号,如果是集群 server,ip 地址不同时,可以选择相同的端口号。

三、server 集群和 client 搭建实战

背景:单机上模拟创建三个 server 以及一个 client。本机系统 centos6.4,zk 版本3.4.12。

配置参考《ZooKeeper 分布式过程协同技术详解》P34

  1. 安装 zk,略。

  2. 设置路径、建立文件夹、配置文件等

    1. ${PATH_TO_ZK}=/root/zookeeper,改成你的 zookeeper 主目录路径

    2. 在 zookeeper 目录下建立文件夹:”z1/data/“、”z1/data/“、”z1/data/“。

    3. 执行

      1
      2
      3
      echo 1 > z1/data/myid
      echo 2 > z2/data/myid
      echo 3 > z3/data/myid
    4. 建立文件”z1/z1.cfg”/“z2/z2.cfg”/“z3/z3.cfg”,写入配置文件:

      1
      2
      3
      4
      5
      6
      7
      8
      tickTime=2000
      initLimit=10
      syncLimit=5
      dataDir=./data
      clientPort=2181 ## z2/z3 中分别改为 2182、2183
      server.1=127.0.0.1:2222:2223
      server.2=127.0.0.1:3333:3334
      server.3=127.0.0.1:4444:4445
    5. 启动 z1、z2 服务器(另开一个终端),3 台 server 启动至少 2 台就可以提供服务了。

      1
      2
      3
      ## 启动 z1 为例
      cd z1
      ${PATH_TO_ZK}/bin/zkServer.sh start ./z1.cfg
  3. 检查 zookeeper.out 日志,确定一个是 leader,另一个是 follower(日志中有明确的字段指示是 following 还是 leading),进入下一步。

  4. 另开一个终端作为 client,执行以下命令,提示 session establishment 以及 complete on server…说明 client 与 zk 的 session 连接完成。

    1
    ${PATH_TO_ZK}/bin/zkCli.sh -server 127.0.0.1
  5. 查看 server 的 status 及单 Server 的停止命令:

    1
    2
    3
    4
    // 在 z2 目录下:
    ${PATH_TO_ZK}/bin/zkServer.sh status ./z2.cfg

    ${PATH_TO_ZK}/bin/zkServer.sh stop ./z2.cfg
  6. 如果 master 挂掉了,那么待转正的备胎会经历以下步骤:

    1. 备胎感知到 master 跪了,自己也会被 interrupted,然后操作一波 shutdown,进入looking 状态,然后进入新的选举;
    2. 备胎当选成功,更新为 leading 状态.
    3. 另一个落选的备胎,也会经历 looking 状态,当选举失败后进入 following 状态。
    4. 如果挂掉的结点刚好是与 Client 建立连接的结点,那么新连接还是会从目前存活的结点中重新建立。
-------------The End-------------