ZooKeeper 典型应用场景

1. ZooKeeper 概述

ZooKeeper 是一个开源的高可用的分布式数据管理与系统协调框架,基于对 Paxos 算法的实现,保证了分布式环境中数据的强一致性

1.1 ZooKeeper 典型应用场景

1.1.1 配置中心(数据发布与订阅)

发布与订阅模型:发布者发布数据到 ZK 节点上,供订阅者动态获取数据。

数据量很少,但是数据更新快的场景下:

  • 配置信息放到 ZK节点上集中管理。应用启动时主动获取一次,同时在节点上注册一个 Watcher,这样每次配置更新时,都会实时通知到订阅的客户端获取。
  • 分布式搜索服务中,索引的元信息 & 服务器集群机器的节点状态存放在 ZK 节点上。
  • 分布式日志收集系统。zk 上创建一个以应用名命名的节点P,这个应用的所有机器 ip,作为子节点注册到节点 P 上,这样能够实时通知收集器调整任务分配。
  • 系统中信息的动态获取,且存在人工手动修改信息的可能。通常是暴露出接口。

1.1.2 负载均衡(软负载均衡)

消息中间件中的发布者和订阅者的负载均衡,linkedin 开源的 KafkaMQ 和 阿里开源的 MetaQ 都是通过 ZooKeeper 来做到生产者 & 消费者的负载均衡:

  1. 生产者负载均衡:MetaQ 运行时,会把所有 broker 和对应的分区信息全部注册到 ZK 节点上,然后生产者通过 ZK 获取分区列表之后,会依次轮询的策略来选择一个分区来发送消息。
  2. 消费者负载均衡:一个消费者可以消费(查看)一个或多个分区中的消息,但是一个分区的消息只会由一个消费者来消费

MetaQ 的消费策略是:

  • 每个分区针对同一个组只挂载一个消费者
  • 如果同一个组的消费者数目大于分区数目,则多余的消费者不参与消费
  • 如果同一个组的消费者数目小于分区数目,则由部分消费者需要额外承担消费任务

当某个消费者故障重启时,其他消费者会感知到(通过 watch 消费者列表),然后重新进行负载均衡,保证所有分区都有消费者进行消费。

1.1.3 命名服务

在分布式系统中,通过使用命名服务,客户端应用通过指定名字获取资源、服务的地址等信息。较为常见的:分布式服务框架中的服务地址列表

阿里巴巴集团开源的分布式服务框架 Dubbo 中使用 ZooKeeper 来作为其命名服务,维护全局的服务地址列表。在 Dubbo 实现中:

  • 服务提供者启动时,向 ZK 上的节点 /dubbo/${serviceName}/providers 目录下写入自己的 URL 地址,这个操作就完成了服务的发布
  • 服务消费者启动时,订阅 /dubbo/${serviceName}/providers 目录下的提供者 URL 地址,并向 /dubbo/${serviceName}/consumers 目录下写入自己的消费者 URL 地址

以上注册的地址都是临时节点,保证服务提供者和消费者能够自动感应资源的变化。

1.1.4 分布式通知/协调

ZooKeeper 中特有的 Watcher 注册异步通知机制,实现分布式环境下不同系统之间的通知协调,实现对数据变更实时处理

也就是说,不同系统都对 ZK 上同一个节点进行注册,监听节点的变化(包括节点本身内容及子节点的),其中一个系统更新了节点,那么另一个系统能够收到通知,并作出相应处理。

  • 另一种心跳检测机制:检测系统和被检测系统之间并不直接关联起来,而是通过 ZK 上某个节点关联,大大减少系统耦合。
  • 另一种系统调度模式:某系统有控制台推送系统两部分组成,控制台的职责就是控制推送系统进行相应的推送工作。管理人员通过控制台修改了 ZK 上某些节点的状态,而 ZK 就会把这些变化通知给他们注册 Watcher 的客户端(推送系统),于是,做出相应的推送任务。
  • 另一种工作汇报模式:类似于任务分发系统,子任务启动后,到 ZK 来注册一个临时节点,并且定时将自己的进度进行汇报(写入节点),这样任务管理者能够实时监控任务进度

总之,使用 ZooKeeper 来进行分布式通知和协调能够大大降低系统之间的耦合。

1.1.5 集群管理与 Master 选举

集群机器监控:通常用于对集群中机器状态、机器在线率有较高要求的场景,能够快速对集群中机器变化作出响应。

利用 ZooKeeper 两个特性,就可以实现集群机器存活性监控系统

  • 客户端在节点 x 上注册一个 Watcher,那么如果 x 的子节点变化了,会通知该客户端。
  • 创建临时节点,一旦客户端和服务器的会话结束或过期,那么该节点就会消失。

Master 选举是 ZooKeeper 中最为经典的应用场景。

在分布式环境中,有些耗时的操作,往往只需让整个集群中的某一台机器进行执行,其余的机器可以共享这个结果。那么谁去执行呢?于是就要靠 Master 选举了。

首先利用 ZooKeeper 的强一致性,保证分布式高并发情况下节点创建的全局唯一性。即:同时有多个客户端请求创建 /currentMaster 节点,但最终一定只有一个客户端请求能够创建成功

其次,如果需要动态 Master 选举,那就要用到 EPHEMERAL_SEQUENTIAL 类型节点。此时,允许所有的请求都能够创建成功,但是有创建顺序,于是每次选取序列号最小的那个机器作为 Master,如果 Master 机器挂了,那么之后最小的机器继续当 Master。

  • 搜索系统中,让集群中的 Master 来进行全局索引的生成,然后同步到集群中其他机器中。此外,Master 选举的容灾措施是:可以随时手动指定 Master(应用在 zk 上无法获取 Master 信息时,可以通过 http 方式,向一个地方获取 master)
  • Hbase 中,也是使用 ZooKeeper 来实现动态 HMaster 的选举

1.1.6 分布式锁

锁服务可以分为两类:保持独占控制时序

  • 保持独占:所有试图获取这个锁的客户端中,只有一个可以成功获得这把锁。做法:把 ZK 上的一个 znode 看做一把锁,所有客户端都去创建 /distribute_lock 节点,最终成功创建的客户端拥有这把锁。
  • 控制时序:所有试图获取这个锁的客户端中,都会按照一个全局时序执行。做法跟上面的基本类似, /distribute_lock 已经预先存在,客户端在它下面创建临时有序节点。ZK 的父节点(/distribute_lock) 维持一份 sequence ,保证子节点创建的时序性,从而形成了每个客户端的全局时序。

1.1.7 分布式队列

队列方面分两种:先进先出队列、等到队列成员聚齐之后才统一按序执行。

第一种:FIFO 队列,与分布式锁服务中你给的控制时序场景原理基本一致。

第二种:FIFO 队列的增强版做法:在 /queue 这个节点下,预先建立一个 /queue/num 节点,并且赋值为 n ,表示队列的大小,当队列成员数到达队列大小时,就开始执行。
第二种用法的典型场景:分布式环境中,一个大任务 TaskA,需要在很多子任务完成(或者条件就绪)情况下才能进行。此时,只要其中一个子任务完成(就绪),就去 /taskList 下建立自己的临时节点,当 /tashList 发现自己下面的子节点满足指定个数,就可以进行下一步按序处理了。

你可能感兴趣的:(ZooKeeper 典型应用场景)