Zookeeper 是一个典型的 分布式数据一致性 的解决方案,是谷歌 Chubby 的开源实现,在分布式系统中有非常广泛的应用。
分布式应用程序可以基于它来实现 数据发布/订阅、分布式协调/通知、集群管理、Master 选举、命名服务、分布式锁和分布式队列 等功能。
在诸如 HDFS、Yarn、HBase、Kafka、Flink 等著名分布式系统中都使用 Zookeeper 来实现各自的 分布式协调机制。
在大数据系统中,Zookeeper 是必不可少的组件,所有大数据平台上必定运行着一组 Zookeeper 服务器集群。
对于大部分业务开发人员来说,Zookeeper 是属于幕后默默干活奉献的角色,在开发过程中接触的往往都是基于 Zookeeper 的上层系统,这使得很多开发人员对 Zookeeper 处于一种 知道它很重要,但是对它缺不熟悉 的状态。
虽然在大部分工作中,开发人员并不需要完全了解 Zookeeper 是如何实现的,但是保持对这个重要组件的了解与探索能够在一定程度上 提升对现有分布式系统实现的理解。
本文将会从 Zookeeper 的 基本概念 开始介绍,随后使用客户端API模拟了一个简单的 Master-Slaves 集群 中主从节点的行为,并在之后讨论到其 内部实现的机制与服务端相关的参数配置,为分布式系统应用揭开最后一层神秘的面纱。
最后我们会列举一些 Zookeeper 集群在业务系统中的 应用场景。
一、基本概念
1.1 构建健壮的分布式系统
要开发实现一个分布式系统并不容易,相对于开发在一台计算机上运行的单个程序,如何让 一个应用中多个独立的程序协同工作 是一件非常困难的事情。
开发这样的应用,很容易让很多开发人员陷入 如何使多个程序协同工作的逻辑 中,最后导致没有时间更好地思考和实现他们自己的应用程序逻辑。又或者开发人员对协同逻辑关注不够,只是用很少的时间开发了一个简单脆弱的主协调器,导致整体服务的不可靠。
Zookeeper 的出现帮开发人员解决了这一难题,让开发人员能够 专注于系统业务功能的开发,而不是陷入分布式环境的细节中不可自拔。
你可以将 Zookeeper 理解为是一种 提供给分布式系统使用的协调工具,给开发人员 提供一套容易理解和开发的接口,从而简化分布式系统构建的任务。所有需要跨多个物理主机,或者独立运行的多个软件组件组成的系统都可以通过使用 Zookeeper 来 简化服务节点之间的交互和协同工作。比如:主节点选举、从节点任务分配、崩溃监测等。
Zookeeper 在为开发人员 屏蔽了分布式系统中的细节问题,最大程度简化系统架构师的工作。
在 Zookeeper 之前,人们通过其他中间件(比如MySQL、Redis等)的辅助也能够实现分布式系统的功能,但是 Zookeeper 出现之后构建分布式系统从未如此简单。
假设现在我们需要实现一个 Master-Slaves 主从结构的集群,这个集群至少能够实现:
- 多主节点互备,并能够进行主节点选举
- 从节点崩溃监测
- 集群节点的任务分配、调度
- 集群元数据管理
想象一下,如果需要你自己在多台机器上实现这些功能会有多大工作量!
但是别担心, Zookeeper 会给我们提供实现这些功能的工具,在接下来的篇幅相信你能够找到实现方案。
1.2 集群架构
如上图所示, Zookeeper 集群中只有两种角色的节点:Server服务端 和 Client客户端。
多台服务端机器组成 Zookeeper 集群,而 HDFS、Yarn、HBase、Kafka、Flink 等系统中则使用 Zookeeper 的客户端来连接服务端并实现自己想要的功能,在 Zookeeper 看来他们都属于客户端节点。
在服务端节点中,还细分为以下三种类型:
- Leader: Leader 是集群中的的主节点,负责响应 所有对 ZooKeeper 状态变更的请求,写操作都走 Leader。
- Follower: Follower 负责处理本服务器上的 读请求,对于写请求会转发给 Leader 进行处理。
- Observer: Observer 作为集群中的 观察节点,本身并 不参加选举也不响应提议、不需要将事务持久化到磁盘,但是可以提供 一定程度的读功能。
服务端上运行的 Zookeeper 进程可能是三种类型的任意一种,谁成为 Leader 谁成为 Follower 是由 选举机制 来决定的,我们会在稍后讨论它。
现在只需要记住, Zookeeper 集群由 服务端和客户端 组成,服务端中有 Leader、Follower、Observer 三种类型的服务各自负责不同的功能即可。
Zookeeper 有两种运行模式:独立模式(Standalone) 和 仲裁模式(Quorum)。
独立模式下, Zookeeper 只有一个服务端,所有客户端都和它交互,如果你对大数据开发感兴趣,想系统学习大数据的话,可以加入大数据技术学习交流扣扣群:458数字345数字782,欢迎添加,私信管理员,了解课程介绍,获取学习资源这对于一个需要高可用的系统来说是不可接受的。
所以一般情况下我们都会使用仲裁模式,也就是集群模式。
在仲裁模式下,由于有 多个服务端同时为客户端提供服务,那么当客户端发出一个写请求后,服务端之间怎么进行数据同步以保证数据的一致性呢?
- 如果客户端写入数据后,如果需要所有服务器同步完成才返回则 延迟会非常高,这显然是不可接受的。
- 反之如果写入一个服务端就返回成功,当该节点宕机就可能造成 数据丢失与服务不可用,这显然也是不能接受的。
仲裁模式下规定,一个客户端的写请求 需要至少 n
个服务端完成数据更新的同步才算此次写请求成功完成。
n
被称为 有效的服务器数量,那么有效的服务器数量如何确认呢?
Zookeeper 规定有效服务器数量需要 大于集群中一半以上的服务器数量:
- n <= 一半:可用性太低,集群若挂了一半的服务,则剩下的服务节点可能是未同步状态,整体服务不可用。
- n > 一半:就算挂了一半的服务器,仍然有 至少一个服务节点数据数据完整的,保证整体服务仍然是可用的,其余节点可以从该节点同步数据。
这种模式可以最大程度保证数据不会因为各种网络问题而丢失。
而且我们建议集群总体数量最好是 奇数:
假设集群共有 f 个节点,则最多能容忍 n 个服务节点宕机,n < f/2。
如果 f 为偶数,比如8,那么能容忍宕机的数量 n 为3(f/2=4,比4小的最大的数为3)。
那么此时,集群中必须要有5个节点确认写入成功,这和 f=7 的集群效果一致,能够容忍的宕机数量 n=3。