zookeeper知识梳理

Zookeeper概述

Zookeeper是一个开源的分布式协调服务,由雅虎创建,用于分布式应用程序的协调和配置管理。Zookeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。

Zookeeper的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。

Zookeeper的核心是一个高性能分布式数据一致性解决方案,分布式应用程序可以基于Zookeeper实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能。

Zookeeper架构

Zookeeper的架构核心是ZAB协议,ZAB协议是Zookeeper内部的一种协议,用于保证分布式数据的一致性。

Zookeeper的架构包括以下几个部分:

  1. Client:客户端,用于与Zookeeper集群进行交互。
  2. Server:服务器,Zookeeper集群中的每个节点都是一个服务器。
  3. Leader:领导者,Zookeeper集群中的一个节点被选举为领导者,负责处理客户端的写请求。
  4. Follower:跟随者,Zookeeper集群中的其他节点被称为跟随者,负责处理客户端的读请求。
  5. Observer:观察者,Zookeeper集群中的一个节点被选举为观察者,负责复制Leader的数据,但不参与投票选举Leader。

Zookeeper的选举机制

Zookeeper的选举机制是基于ZAB协议实现的,选举过程如下:

  1. 每个节点都有一个递增的编号,称为ZXID,ZXID越大表示节点越新。
  2. 当一个节点启动时,它会向集群中的其他节点发送一个消息,请求投票。
  3. 其他节点收到消息后,会比较自己的ZXID和请求节点的ZXID,如果请求节点的ZXID更大,则投票给请求节点。
  4. 如果一个节点收到超过半数的投票,则成为Leader,否则继续等待投票。

获得超过集群半数选票的节点成为Leader,当已经产生了Leader后, 即使后加入的节点的ZXID更大也不会成为Leader, 而是成为Follower。

Zookeeper数据模型

Zookeeper的数据模型是一个树形结构,类似于文件系统的目录结构,每个节点称为ZNode,每个ZNode可以存储数据和子节点。

ZNode有以下几种类型:

  1. 持久节点(Persistent):创建后一直存在,直到被删除。
  2. 临时节点(Ephemeral):客户端会话结束后被删除。
  3. 有序节点(Sequential):在节点名称后面追加一个递增的序号。

ZNode的路径是唯一的,类似于文件系统的路径,可以通过路径访问ZNode。

数据一致性

为了实现分布式的数据协调, 最重要的就是保证数据的一致性. Zookeeper通过如下几个方面来保证数据的一致性:

版本号控制

Zookeeper为每个ZNode维护了一个版本号, 包括数据版本号和ACL版本号, 当ZNode的数据发生变化时, 数据版本号会自增, 客户端可以通过版本号来判断数据是否发生变化, 避免脏写问题.

事务日志

Zookeeper会将每次写操作记录到事务日志中, 保证数据的持久性, 当Zookeeper重启时, 可以通过回放事务日志来恢复数据. 事务日志存储于磁盘, 保证数据的持久性. 除了日志之外, Zookeeper还有快照机制, 定期将内存中的数据持久化到磁盘, 以提高恢复速度. 事务日志和快照分别对应增量备份和全量备份, 保证数据的可靠性.

半数机制+2PC机制

2PC: 2 Phase Commit, 两阶段提交, 保证数据的一致性. 在Zookeeper中, 写操作分为事务和提交两个阶段:

事务阶段

当数据发送到leader节点后, leader会产生一个新的事务并创建一个zxid, leader会将数据同步给follower节点, follower节点会将事务日志持久化, 并向leader节点发送ACK确认消息.

提交阶段

当leader节点收到超过半数的follower节点的ACK确认消息后, leader会向所有follower节点发送异步commit消息, 并向调用者返回成功响应. follower节点收到commit消息后, 会更新自己的数据库数据.

因此通常Zookeeper集群会有奇数个节点, 以保证半数机制的高效性

通过半数机制+2PC机制, Zookeeper保证了数据的一致性, 保证了数据的可靠性.

Zookeeper的应用场景

Zookeeper的应用场景非常广泛,主要包括以下几个方面:

1. 数据发布/订阅

Zookeeper可以用于发布和订阅数据,客户端可以监听ZNode的变化。 常用于配置中心构建, 实现配置的集中管理和动态更新, 维护例如全局配置/地址列表等配置数据。
当配置数据发生变化时,服务端会通过watch机制通知客户端, 客户端再主动前往Zookeeper获取最新的配置数据。

2. 命名服务

Zookeeper可以用于实现命名服务,客户端可以通过ZNode的路径来获取服务的地址。例如域名和IP地址的映射, 服务发现等。
常用于服务注册与发现, 实现服务的动态注册和发现, 服务提供者将服务地址注册到Zookeeper, 服务消费者通过Zookeeper获取服务地址。

3. 集群管理

Zookeeper可以用于集群管理,例如Master选举、Leader选举等。

例子: HBASE中的Master选举和监控就是通过Zookeeper实现的, 具体来说, HBASE集群中的每个RegionServer都会在Zookeeper上创建一个临时节点, 用于表示自己的存活状态, Master节点会监控这些临时节点, 当发现某个RegionServer的临时节点消失时, 就会触发Master选举。

4. 分布式通知/协调

Zookeeper可以用于实现分布式通知和协调,例如分布式锁、分布式队列等。

分布式锁

分布式锁是指多个进程或者多个线程在不同的机器上,通过共享的资源来实现同步的目的。为了实现分布式锁,可以在Zookeeper上通过临时节点实现,流程步骤大概是:

  1. 多个使用者都在同一个节点下面创建带有序号的临时节点;
  2. 当需要获取锁时, 判断自己创建的节点是否是当前序号最小的节点, 如果是则获取锁, 否则监听前一个节点的删除事件, 一旦前一个节点被删除, 重新判断自己的节点是否是当前序号最小的节点, 以此类推;
  3. 当使用者释放锁时, 删除自己创建的节点即可, 触发其他使用者的监听事件, 重新判断是否可以获取锁。

分布式队列

分布式队列是指多个进程或者多个线程在不同的机器上,通过共享的队列来实现消息的传递。为了实现分布式队列,可以在Zookeeper上通过有序节点实现, 实现类似于生产者消费者使用场景