5分钟让你了解 ZooKeeper 的原理

本文转自公众号:大数据架构之路(ID:FullStackPlan 

作者:LBD

前言

ZooKeeper 是一个开源的分布式协调服务,由雅虎创建,是 Google Chubby 的开源实现。分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。

1、简介

ZooKeeper 是一个开源的分布式协调服务,由雅虎创建,是 Google Chubby 的开源实现。分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。

2、基本概念

本节将介绍 ZooKeeper 的几个核心概念。这些概念贯穿于之后对 ZooKeeper 更深入的讲解,因此有必要预先了解这些概念。

2.1 集群角色

在 ZooKeeper 中,有三种角色:

  • Leader

  • Follower

  • Observer

一个 ZooKeeper 集群同一时刻只会有一个 Leader,其他都是 Follower 或 Observer。

ZooKeeper 配置很简单,每个节点的配置文件(zoo.cfg)都是一样的,只有 myid 文件不一样。myid 的值必须是 zoo.cfg中server.{数值}{数值}部分。

zoo.cfg 文件内容示例:

在装有 ZooKeeper 的机器的终端执行 zookeeper-server status 可以看当前节点的 ZooKeeper 是什么角色(Leader or Follower)。

如上,node-20-104 是 Leader,node-20-103 是 follower。

ZooKeeper 默认只有 Leader 和 Follower 两种角色,没有 Observer 角色。为了使用 Observer 模式,在任何想变成Observer的节点的配置文件中加入:peerType=observer 并在所有 server 的配置文件中,配置成 observer 模式的 server 的那行配置追加 :observer,例如:

server.1:localhost:2888:3888:observer

ZooKeeper 集群的所有机器通过一个 Leader 选举过程来选定一台被称为『Leader』的机器,Leader服务器为客户端提供读和写服务。

Follower 和 Observer 都能提供读服务,不能提供写服务。两者唯一的区别在于,Observer 机器不参与 Leader 选举过程,也不参与写操作的『过半写成功』策略,因此 Observer 可以在不影响写性能的情况下提升集群的读性能。

2.2 会话(Session)

Session 是指客户端会话,在讲解客户端会话之前,我们先来了解下客户端连接。在 ZooKeeper 中,一个客户端连接是指客户端和 ZooKeeper 服务器之间的TCP长连接。

ZooKeeper 对外的服务端口默认是2181,客户端启动时,首先会与服务器建立一个TCP连接,从第一次连接建立开始,客户端会话的生命周期也开始了,通过这个连接,客户端能够通过心跳检测和服务器保持有效的会话,也能够向 ZooKeeper 服务器发送请求并接受响应,同时还能通过该连接接收来自服务器的 Watch 事件通知。

Session 的 SessionTimeout 值用来设置一个客户端会话的超时时间。当由于服务器压力太大、网络故障或是客户端主动断开连接等各种原因导致客户端连接断开时,只要在 SessionTimeout 规定的时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话仍然有效。

2.3 数据节点(ZNode)

在谈到分布式的时候,一般『节点』指的是组成集群的每一台机器。而ZooKeeper 中的数据节点是指数据模型中的数据单元,称为 ZNode。ZooKeeper 将所有数据存储在内存中,数据模型是一棵树(ZNode Tree),由斜杠(/)进行分割的路径,就是一个ZNode,如 /hbase/master,其中 hbase 和 master 都是 ZNode。每个 ZNode 上都会保存自己的数据内容,同时会保存一系列属性信息。

注:

这里的 ZNode 可以理解成既是Unix里的文件,又是Unix里的目录。因为每个 ZNode 不仅本身可以写数据(相当于Unix里的文件),还可以有下一级文件或目录(相当于Unix里的目录)。

在 ZooKeeper 中,ZNode 可以分为持久节点和临时节点两类。

  • 持久节点

所谓持久节点是指一旦这个 ZNode 被创建了,除非主动进行 ZNode 的移除操作,否则这个 ZNode 将一直保存在 ZooKeeper 上。

  • 临时节点

临时节点的生命周期跟客户端会话绑定,一旦客户端会话失效,那么这个客户端创建的所有临时节点都会被移除。

另外,ZooKeeper 还允许用户为每个节点添加一个特殊的属性:SEQUENTIAL。一旦节点被标记上这个属性,那么在这个节点被创建的时候,ZooKeeper 就会自动在其节点后面追加上一个整型数字,这个整型数字是一个由父节点维护的自增数字。

2.4 版本

ZooKeeper 的每个 ZNode 上都会存储数据,对应于每个 ZNode,ZooKeeper 都会为其维护一个叫作 Stat 的数据结构,Stat 中记录了这个 ZNode 的三个数据版本,分别是 version(当前ZNode的版本)、cversion(当前ZNode子节点的版本)和 aversion(当前 ZNode 的 ACL 版本)。

2.5 状态信息

每个 ZNode 除了存储数据内容之外,还存储了 ZNode 本身的一些状态信息。用 get 命令可以同时获得某个 ZNode 的内容和状态信息。如下:

在 ZooKeeper 中,version 属性是用来实现乐观锁机制中的『写入校验』的(保证分布式数据原子性操作)。

2.6 事务操作

在ZooKeeper中,能改变ZooKeeper服务器状态的操作称为事务操作。一般包括数据节点创建与删除、数据内容更新和客户端会话创建与失效等操作。对应每一个事务请求,ZooKeeper 都会为其分配一个全局唯一的事务ID,用 ZXID 表示,通常是一个64位的数字。每一个 ZXID 对应一次更新操作,从这些 ZXID 中可以间接地识别出 ZooKeeper 处理这些事务操作请求的全局顺序。

2.7 Watcher

Watcher(事件监听器),是 ZooKeeper 中一个很重要的特性。ZooKeeper允许用户在指定节点上注册一些 Watcher,并且在一些特定事件触发的时候,ZooKeeper 服务端会将事件通知到感兴趣的客户端上去。该机制是 ZooKeeper 实现分布式协调服务的重要特性。

2.8 ACL

ZooKeeper 采用 ACL(Access Control Lists)策略来进行权限控制。ZooKeeper 定义了如下5种权限。

  • CREATE: 创建子节点的权限。

  • READ: 获取节点数据和子节点列表的权限。

  • WRITE:更新节点数据的权限。

  • DELETE: 删除子节点的权限。

  • ADMIN: 设置节点ACL的权限。

注意:CREATE 和 DELETE 都是针对子节点的权限控制。

3. ZooKeeper典型应用场景

ZooKeeper 是一个高可用的分布式数据管理与协调框架。基于对ZAB算法的实现,该框架能够很好地保证分布式环境中数据的一致性。也是基于这样的特性,使得 ZooKeeper 成为了解决分布式一致性问题的利器。

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

数据发布与订阅,即所谓的配置中心,顾名思义就是发布者将数据发布到 ZooKeeper 节点上,供订阅者进行数据订阅,进而达到动态获取数据的目的,实现配置信息的集中式管理和动态更新。

在我们平常的应用系统开发中,经常会碰到这样的需求:系统中需要使用一些通用的配置信息,例如机器列表信息、数据库配置信息等。这些全局配置信息通常具备以下3个特性。

  • 数据量通常比较小。

  • 数据内容在运行时动态变化。

  • 集群中各机器共享,配置一致。

对于这样的全局配置信息就可以发布到 ZooKeeper上,让客户端(集群的机器)去订阅该消息。

发布/订阅系统一般有两种设计模式,分别是推(Push)和拉(Pull)模式。

  • 推:服务端主动将数据更新发送给所有订阅的客户端。

  • 拉:客户端主动发起请求来获取最新数据,通常客户端都采用定时轮询拉取的方式。

ZooKeeper 采用的是推拉相结合的方式。如下:

客户端想服务端注册自己需要关注的节点,一旦该节点的数据发生变更,那么服务端就会向相应的客户端发送Watcher事件通知,客户端接收到这个消息通知后,需要主动到服务端获取最新的数据(推拉结合)。

3.2 命名服务(Naming Service)

命名服务也是分布式系统中比较常见的一类场景。在分布式系统中,通过使用命名服务,客户端应用能够根据指定名字来获取资源或服务的地址,提供者等信息。被命名的实体通常可以是集群中的机器,提供的服务,远程对象等等——这些我们都可以统称他们为名字(Name)。

其中较为常见的就是一些分布式服务框架(如RPC、RMI)中的服务地址列表。通过在ZooKeepr里创建顺序节点,能够很容易创建一个全局唯一的路径,这个路径就可以作为一个名字。

ZooKeeper 的命名服务即生成全局唯一的ID。

3.3 分布式协调/通知

ZooKeeper 中特有 Watcher 注册与异步通知机制,能够很好的实现分布式环境下不同机器,甚至不同系统之间的通知与协调,从而实现对数据变更的实时处理。使用方法通常是不同的客户端都对ZK上同一个 ZNode 进行注册,监听 ZNode 的变化(包括ZNode本身内容及子节点的),如果 ZNode 发生了变化,那么所有订阅的客户端都能够接收到相应的Watcher通知,并做出相应的处理。

ZK的分布式协调/通知,是一种通用的分布式系统机器间的通信方式。

3.3.1 心跳检测

机器间的心跳检测机制是指在分布式环境中,不同机器(或进程)之间需要检测到彼此是否在正常运行,例如A机器需要知道B机器是否正常运行。在传统的开发中,我们通常是通过主机直接是否可以相互PING通来判断,更复杂一点的话,则会通过在机器之间建立长连接,通过TCP连接固有的心跳检测机制来实现上层机器的心跳检测,这些都是非常常见的心跳检测方法。

下面来看看如何使用ZK来实现分布式机器(进程)间的心跳检测。

基于ZK的临时节点的特性,可以让不同的进程都在ZK的一个指定节点下创建临时子节点,不同的进程直接可以根据这个临时子节点来判断对应的进程是否存活。通过这种方式,检测和被检测系统直接并不需要直接相关联,而是通过ZK上的某个节点进行关联,大大减少了系统耦合。

3.3.2 工作进度汇报

在一个常见的任务分发系统中,通常任务被分发到不同的机器上执行后,需要实时地将自己的任务执行进度汇报给分发系统。这个时候就可以通过ZK来实现。在ZK上选择一个节点,每个任务客户端都在这个节点下面创建临时子节点,这样便可以实现两个功能:

  • 通过判断临时节点是否存在来确定任务机器是否存活。

  • 各个任务机器会实时地将自己的任务执行进度写到这个临时节点上去,以便中心系统能够实时地获取到任务的执行进度。

3.4 Master选举

Master 选举可以说是 ZooKeeper 最典型的应用场景了。比如 HDFS 中 Active NameNode 的选举、YARN 中 Active ResourceManager 的选举和 HBase 中 Active HMaster 的选举等。

针对 Master 选举的需求,通常情况下,我们可以选择常见的关系型数据库中的主键特性来实现:希望成为 Master 的机器都向数据库中插入一条相同主键ID的记录,数据库会帮我们进行主键冲突检查,也就是说,只有一台机器能插入成功——那么,我们就认为向数据库中成功插入数据的客户端机器成为Master。

依靠关系型数据库的主键特性确实能够很好地保证在集群中选举出唯一的一个Master。

但是,如果当前选举出的 Master 挂了,那么该如何处理?谁来告诉我 Master 挂了呢?显然,关系型数据库无法通知我们这个事件。但是,ZooKeeper 可以做到!

利用 ZooKeepr 的强一致性,能够很好地保证在分布式高并发情况下节点的创建一定能够保证全局唯一性,即 ZooKeeper 将会保证客户端无法创建一个已经存在的 ZNode。

也就是说,如果同时有多个客户端请求创建同一个临时节点,那么最终一定只有一个客户端请求能够创建成功。利用这个特性,就能很容易地在分布式环境中进行 Master 选举了。

成功创建该节点的客户端所在的机器就成为了 Master。同时,其他没有成功创建该节点的客户端,都会在该节点上注册一个子节点变更的 Watcher,用于监控当前 Master 机器是否存活,一旦发现当前的Master挂了,那么其他客户端将会重新进行 Master 选举。

这样就实现了 Master 的动态选举。

3.5 分布式锁

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。

分布式锁又分为排他锁和共享锁两种。

3.5.1 排他锁

排他锁(Exclusive Locks,简称X锁),又称为写锁或独占锁。

如果事务T1对数据对象O1加上了排他锁,那么在整个加锁期间,只允许事务T1对O1进行读取和更新操作,其他任何事务都不能在对这个数据对象进行任何类型的操作(不能再对该对象加锁),直到T1释放了排他锁。

可以看出,排他锁的核心是如何保证当前只有一个事务获得锁,并且锁被释放后,所有正在等待获取锁的事务都能够被通知到。

如何利用 ZooKeeper 实现排他锁?

  • 定义锁

ZooKeeper 上的一个 ZNode 可以表示一个锁。例如 /exclusive_lock/lock节点就可以被定义为一个锁。

  • 获得锁

如上所说,把ZooKeeper上的一个ZNode看作是一个锁,获得锁就通过创建 ZNode 的方式来实现。所有客户端都去 /exclusive_lock节点下创建临时子节点 /exclusive_lock/lock。ZooKeeper 会保证在所有客户端中,最终只有一个客户端能够创建成功,那么就可以认为该客户端获得了锁。同时,所有没有获取到锁的客户端就需要到/exclusive_lock节点上注册一个子节点变更的Watcher监听,以便实时监听到lock节点的变更情况。

  • 释放锁

因为 /exclusive_lock/lock 是一个临时节点,因此在以下两种情况下,都有可能释放锁。

  • 当前获得锁的客户端机器发生宕机或重启,那么该临时节点就会被删除,释放锁。

  • 正常执行完业务逻辑后,客户端就会主动将自己创建的临时节点删除,释放锁。

无论在什么情况下移除了lock节点,ZooKeeper 都会通知所有在 /exclusive_lock 节点上注册了节点变更 Watcher 监听的客户端。这些客户端在接收到通知后,再次重新发起分布式锁获取,即重复『获取锁』过程。

3.5.2 共享锁

共享锁(Shared Locks,简称S锁),又称为读锁。如果事务T1对数据对象O1加上了共享锁,那么T1只能对O1进行读操作,其他事务也能同时对O1加共享锁(不能是排他锁),直到O1上的所有共享锁都释放后O1才能被加排他锁。

总结:可以多个事务同时获得一个对象的共享锁(同时读),有共享锁就不能再加排他锁(因为排他锁是写锁)

4、ZooKeeper在大型分布式系统中的应用

前面已经介绍了 ZooKeeper 的典型应用场景。本节将以常见的大数据产品 Hadoop 和 HBase 为例来介绍 ZooKeeper 在其中的应用,帮助大家更好地理解 ZooKeeper 的分布式应用场景。

4.1 ZooKeeper在Hadoop中的应用

在 Hadoop 中,ZooKeeper 主要用于实现 HA(Hive Availability),包括 HDFS的 NamaNode 和 YARN 的 ResourceManager 的 HA。同时,在 YARN 中, ZooKeepr 还用来存储应用的运行状态。

HDFS 的 NamaNode 和 YARN 的 ResourceManager 利用 ZooKeepr 实现 HA 的原理是一样的,所以本节以YARN为例来介绍。

从上图可以看出,YARN主要由ResourceManager(RM)、NodeManager(NM)、ApplicationMaster(AM)和Container四部分组成。其中最核心的就是ResourceManager。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值