Zookeeper相关总结(初阶)

84 阅读10分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情

Zookeeper的介绍

Zookeeper 本是雅虎研究院内部孵化出的一款分布式协调中间件,后来在2011年11月正式成为了 apache 顶级开源项目

关于 Zookeeper 的由来也是非常的有趣 :

ZooKeeper 最早起源于雅虎研究院的一个研究小组。在当时,研究人员发现,在雅虎内部很多大型系统基本都需要依赖一个类似的系统来进行分布式协调,但是这些系统往往都存在分布式单点问题。所以,雅虎的开发人员就试图开发一个通用的无单点问题的分布式协调框架,以便让开发人员将精力集中在处理业务逻辑上。

关于“ZooKeeper”这个项目的名字,其实也有一段趣闻。在立项初期,考虑到之前内部很多项目都是使用动物的名字来命名的(例如著名的 Pig 项目),雅虎的工程师希望给这个项目也取一个动物的名字。时任研究院的首席科学家 RaghuRamakrishnan 开玩笑地说:“再这样下去,我们这儿就变成动物园了!”此话一出,大家纷纷表示就叫动物园管理员吧一一一因为各个以动物命名的分布式组件放在一起,雅虎的整个分布式系统看上去就像一个大型的动物园了,而 ZooKeeper 正好要用来进行分布式环境的协调一一于是,ZooKeeper 的名字也就由此诞生了。 -- 摘抄自《从 Paxos 到 ZooKeeper 》

Zookeeper相关概述

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

"原语" 这个词是操作系统或计算机网络用语范畴。意思是由若干条指令组成的,用于完成一定功能的一个过程。具有不可分割性·即原语的执行必须是连续的,在执行过程中不允许被中断。

ZooKeeper 为我们提供了高可用、高性能、稳定的分布式数据一致性解决方案,分布式应用程序通常可以基于它实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。

另外,ZooKeeper 将数据保存在内存中,性能是非常棒的。 在“读”多于“写”的应用程序中尤其地高性能,因为“写”会导致所有的服务器间同步状态。(“读”多于“写”是协调服务的典型场景)。

Zookeeper的特点

  • 顺序一致性:从同一个客户端发送数据到 Zookeeper ,Zookeeper 会严格的按照其发送的顺序来进行处理

  • 原子性:所有的请求处理结果在 Zookeeper 集群中所有的节点上都是一致的,在处理过程中要么一起成功要么一起失败

  • 单一视图:无论客户端连接到 Zookeeper 集群中的哪台机器,看到的数据模型都是一致的

  • 可靠性:一旦有客户端的请求对 Zookeeper 里的数据或服务状态进行了修改,并成功响应了,那么这次修改数据或服务状态会一直保留下来,除非有另外的一个请求对其进行了修改

  • 实时性: Zookeeper 里的一旦有数据或服务状态被修改,那么客户端就能够立即读取到修改后的最新数据状态

Zookeeper的应用场景

上面就讲到了 Zookeeper 可以用来做数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能

下面来例举三种最为典型的应用场景来说说:

1、注册中心:我们学习过Dubbo应该都知道,通过把服务调用地址注册到 Zookeeper 上,然后Dubbo通过 Watcher 机制进行监听,并拉取远程服务的调用地址

2、分布式锁:我们有了解过 Redis 可以用来做分布式锁,但是 Zookeeper 也同样可以,我们可以利用 Zookeeper 创建唯一节点的来实现,创建了唯一节点就获取到锁,删除唯一节点就释放锁

3、数据的发布/订阅:Zookeeper 提供了 Wacher 监听机制,可以很方便的实现发布/订阅功能

除了上面的一些使用场景外,另外很多的开源项目也使用到了 Zookeeper ,比如 Kafka、HBase、Hadoop 等

Zookeeper的相关概念

数据模型

Zookeeper 的所有数据都是保存在内存中的( Zookeeper 也提供了持久化机制),其存储结构采用的是层次化的多叉树形结构,有点类似于 Unix 文件系统路径

最上层是根节点以 “/” 来代表,开发人员可以在节点下写入数据,数据以二进制进行存储,也可以创建节点,每个节点在 Zookeeper 中被称为 znode ,它是 Zookeeper 中数据的最小单位,并且每个 znode 都有一个唯一的ID

具体存储结构如下图所示:

image.png

znode 数据节点

znode 节点是 zookeeper 中数据的最小单位,它一共分为四种类型:

持久节点(PERSISTENT): 所谓持久节点是指数据节点被创建的后就会一直存在于Zookeeper 上,直到有删除操作来主动删除这个节点。持久节点是 Zookeeper 中最为常用的节点

持久顺序节点(PERSIS_SEQUENTIAL): 除了与持久节点的特性一致之外,其创建的节点还需有顺序性

临时节点(EPHEMERAL): 与上面两个节点不同的是,临时节点具有生命周期,其生命周期与客户端的会话绑定在一起,也就是说,如果客户端的会话失效了,那么这个节点就会被自动清理掉

临时顺序节点(EPHEMERAL_SEQUENTIAL):临时顺序节点与临时节点的特性也基本一致,同样也是多了一个具有顺序的特性

znode 节点信息

znode 节点除了存储的数据外,其本身还有一些状态信息,我们在 Zookeeper 的客户端可以通过 get 命令获取,如下:

[zk: 127.0.0.1:2181(CONNECTED) 6] get /demo
cZxid = 0x2
ctime = Tue Nov 27 11:05:34 CST 2018
mZxid = 0x2
mtime = Tue Nov 27 11:05:34 CST 2018
pZxid = 0x3
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1

下面我们来看下每个信息代表什么吧

cZxid:create ZXID,该数据节点被创建时的事务 id

ctime:create time,即该节点的创建时间

mZxid:modified ZXID,即该节点最终一次更新时的事务 id

mtime:modified time,即该节点最后一次的更新时间

pZxid: 该节点的子节点列表最后一次修改时的事务 id,只有子节点列表变更才会更新 pZxid,子节点内容变更不会更新

cversion: 子节点版本号,当前节点的子节点每次变化时值增加 1

dataVersion: 数据节点内容版本号,节点创建时为 0,每更新一次节点内容(不管内容有无变化)该版本号的值增加 1

aclVersion:节点的 ACL 版本号,表示该节点 ACL 信息变更次数

ephemeralOwner:创建该临时节点的会话的 sessionId;如果当前节点为持 久节点,则 ephemeralOwner=0

dataLength: 数据节点内容长度

numChildren:当前节点的子节点个数

版本

Zookeeper 为节点信息引入了版本号的概念,每个数据节点都有对应的三个版本信息字段,任何对节点的修改都会触发版本号的变化,这三个版本信息字段分别为:

dataVersion: 当前数据节点数据内容的版本号

cversion: 当前数据节点子节点的版本号

aclVersion:节点的 ACL 版本号,表示该节点 ACL 信息变更次数

Wacher 事件监听器

Wacher 机制是 Zookeeper 非常重要的一个特性,Zookeeper 的消息发布/订阅就是通过 Wacher 机制来完成,除此之外 Zookeeper 也允许客户端自定义注册事件监听,当事件触发后,Zookeeper 会主动通知客户端

image.png

会话(Session)

Session 可以看作是 ZooKeeper 服务器与客户端的之间的一个 TCP 长连接,通过这个连接,客户端能够通过心跳检测与服务器保持有效的会话,也能够向 ZooKeeper 服务器发送请求并接受响应,同时还能够通过该连接接收来自服务器的 Watcher 事件通知。

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

另外,在为客户端创建会话之前,服务端首先会为每个客户端都分配一个 sessionID。由于 sessionID 是 ZooKeeper 会话的一个重要标识,许多与会话相关的运行机制都是基于这个 sessionID 的,因此,无论是哪台服务器为客户端分配的 sessionID,都务必保证全局唯一。

Zookeeper 集群

Zookeeper 为了保证高可用,也提供了集群的支持,一般 3 台 Zookeeper 就能够组成一个集群,集群模式为 Master/Savle (主从) 模式,这种集群模式 Master 服务器统一对外提供服务,Savle 服务器只用作数据同步及备份

对应的集群架构如下:

image.png

每台 Zookeeper 服务之间都保持着通讯,通过ZAB协议来保证数据的一致性

Zookeeper 集群角色

虽然 Zookeeper 集群模式是主动模式,但是Zookeeper并没有使用传统的"主","从"概念,而是引用了Leader、Follower 和 Observer 三种角色,如下图所示:

image.png

Leader 可以为客户端提供读写服务,Follwer 和 Observer 除了能只能提供读服务,而 Follwer 与 Observer 主要区别在于 Observer 不参与 Leader 的选举,也不参与写操作的 “过半写成功” 策略

Observer 存在的作用就在于为 Leader 分担读请求,从而提高整个集群的读性能

集群选举机制

当 Leader 节点宕机之后,其他的节点会通过心跳的机制立马检测到,然后各个 Follwer 节点会进行选举,然后通过投票的形式来选举其中某个 Follwer 节点为 Leader 节点

选举的过程大致如下:

1、Leader 节点宕机,各个 Follwer 节点检测到,开始将自己的状态改为 LOOKING 状态

2、各个 Follwer 节点直接开始互相发送投票,投票信息的由 myid (进程ID) 和 ZXID (最大事务ID) 组成

3、Follwer 接收到其他 Follwer 节点的投票信息之后,开始与自己的投票信息进行比对,比对完成之后,会再一次将投票信息发送给其他的 Follwer 节点,比对规则如下:

  • 假设 Follwer1 接收到了 Follwer2 投票信息,那么 Follwer1 会拿自己的投票中 的 ZXID 和 Follwer2 投票信息中的 ZXID 进行比较,如果比 Follwer2 投票信息 中的 ZXID 小,则将自己的选票改为 Follwer2 节点的

4、其他的 Follwer 节点收到之后,会对投票结果进行统计,统计出投票数过半的 Follwer 节点,并将其设置为 Leader

ZooKeeper 集群中的服务器状态

LOOKING :开始进入到选举周期中的状态。

LEADING :Leader 状态,对应的节点为 Leader

FOLLOWING :Follower 状态,对应的节点为 Follower

OBSERVING :Observer 状态,对应节点为 Observer,该节点不参与 Leader 选举