Part 1 -- ZOOKEEPER 概要


ZooKeeper < 一 > 应用场景

A Distributed Coordination Service for Distributed Applications

这是 ZooKeeper 官方文档上的一句话,意为: 一款为分布式应用而生的分布式协同服务。

ZooKeeper version: 3.6.0

ZooKeeper 架构

ZooKeeper Architecture

zk 集群通常包含

1. 角色

  • Leader:或者叫 Master
    • zk集群(官方称之为 ensemble) 中,同一时间只有一个 leader,如果有多个,我们称之为 脑裂(网络分区可能产生这种情况)
    • leader 节点负责 ensemble 中所有的写操作,完成后广播给各个节点
    • leader 节点负责发起并维护与各个 follower/observer 的心跳。如果 leader 宕机,follower 收不到心跳,就会发起选举
  • Follower:
    • 负责与之连接的 client 的读请求
    • 负责将写请求转发给 leader
    • 响应 leader 的心跳
    • 参与选举
  • Observer:不参与投票!其他与 Follower 功能一致

2. 组件

2.1 ZNode(zookeeper data node)

org.apache.zookeeper.CreateMode 枚举类中,共有 7 中 znode 类型,我们一一介绍:

  • PERSISTENT : flag=0,持久节点,除非主动删除,否则一直存在
  • PERSISTENT_SEQUENTIAL : flag = 2,持久顺序节点,该节点会带上一个单调递增的 10 位序列号
  • EPHEMERAL :flag = 1,临时节点,会话结束即被删除
  • EPHEMERAL_SEQUENTIAL :flag = 3,临时顺序节点,会话结束即被删除
  • CONTAINER : flag = 4, 容器节点,当该节点下所有子节点被删除后, 该节点将在将来的某个时刻被删除
  • PERSISTENT_WITH_TTL : flag = 5,该节点在客户端断开时不会被删除,但若在给定的 TTL 范围内没有修改,且没有子节点时, 将被删除
  • PERSISTENT_SEQUENTIAL_WITH_TTL : flag = 6, 同上,多了顺序

2.2 ACL

点击这里

2.3 Watcher

点击这里

2.4 ZAB

点击这里

ZooKeeper 常用应用场景

1. 命名服务

我们知道,zk 的顺序节点特性,就是创建的节点名后,会被加上一个单调递增的 10 位序列号。利用这个特性,我们可以实现全局统一命名服务。

  1. client1 向 /_namespace/_type1 节点下创建 _name 顺序节点,拼接后, _namespace_type1_name0000000001

  2. client2 向 /_namespace/_type2 节点下创建 _name 顺序节点,会获得, _namespace_type2_name0000000002

    zk namespace server

这样就实现了统一命名

2. 分布式锁

分布式锁在这里可以分为两种

  • 抢占式
  • 非抢占式

对于抢占式分布式锁而言,可以利用 zk 的临时节点特性。

每个需要 Lock 的 client 向 zk 的 /lock 节点下创建 /get_lock 子节点(临时节点),创建成功的 client 获得锁,完成后删除该临时节点。

其他 client 在创建失败后,watch 该节点,一旦发现被删除,再次试图创建 /get_lock ,成功即可获得锁。

对于非抢占式而言,可以利用 zk 的临时顺序节点特性。

每个需要 Lock 的 client ,在 /lock 节点下创建 /get_lock 临时顺序节点,成功后获取 /lock 节点下所有子节点,如果序号是最小的,则获取锁,否则 watch 上一个节点,收到 delete event 后即可获得 lock,使用完删除节点,释放锁

lock flow

3. 发布订阅

服务发现,配置中心,都是一样。

这里以 dubbo zookeeper registry 的实现为例,如何利用 zk 的 临时节点,来完成服务发现

Dubbo ZooKeeper Registry Flow

这里令 /root = /dubbo/com.foo.BarService

  • 首先启动服务提供者,会向 zk 的 /root/providers 节点下,写入自己的 URL 地址(临时节点)

  • 然后启动服务消费者,会对 /root/providers 添加 watch,或者说是订阅,同时向 /root/consumers 节点下写入自己的 URL 地址(临时节点)

  • 监控中心(一般为 dubbo admin)启动,watch 或者说订阅整个 /root 节点的 children,这样,当 provider 或者 consumer 发生变动时,我们就能及时的通过 dubbo admin 观察到

4. Master 选举

所谓 Master 选举,这里说的并不是 zk 的 leader 选举。

在分布式系统下,我们常常会遇到定时任务这种场景。比如在凌晨四点(凌晨再也没有四点了… )统计昨天的商品报表,我们只需要一个 server 去跑就好了。这里就可以利用 zk 的临时节点特性。

同样的,每台 server 在 run job 时,先去 zk 注册一个特定临时节点,比如 /item/_statistics ,由创建成功的 server 去执行就好

5. others

  • 集群监控: 做法类似,每台 server 到指定节点下(如 _monitor)注册一个 ephemeral 类型节点,监控端负责 watch _monitor ,当有机器加入或者掉线,就会收到通知
  • 分布式队列(FIFO):利用 zk 的临时有序节点特性,在指定节点下创建临时有序节点后获取所有子节点,如果自己序号最小,则执行
  • 负载均衡:利用临时节点特性,server 在指定节点创建临时节点,客户端读取节点下所有子节点列表,选择 server 服务

ISSUE

New in 3.6.0: Clients can also set permanent, recursive watches on a znode that are not removed when triggered and that trigger for changes on the registered znode as well as any children znodes recursively.

3.6.0 已经开始支持永久的 watch 了

参考文档

ZooKeeper 官方文档 r3.6.0

GITHUB

Dubbo ZooKeeper Registry


文章作者: peifeng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 peifeng !
  目录