1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-06-16 18:10:13 +08:00
2019-07-07 22:15:22 +08:00

186 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

![](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-9-10/56385654.jpg)
## 前言
相信大家对 ZooKeeper 应该不算陌生。但是你真的了解 ZooKeeper 是个什么东西吗?如果别人/面试官让你给他讲讲 ZooKeeper 是个什么东西,你能回答到什么地步呢?
我本人曾经使用过 ZooKeeper 作为 Dubbo 的注册中心,另外在搭建 solr 集群的时候,我使用到了 ZooKeeper 作为 solr 集群的管理工具。前几天,总结项目经验的时候,我突然问自己 ZooKeeper 到底是个什么东西想了半天脑海中只是简单的能浮现出几句话“①Zookeeper 可以被用作注册中心。 ②Zookeeper 是 Hadoop 生态系统的一员;③构建 Zookeeper 集群的时候,使用的服务器最好是奇数台。” 可见,我对于 Zookeeper 的理解仅仅是停留在了表面。
所以,**通过本文,希望带大家稍微详细的了解一下 ZooKeeper 。如果没有学过 ZooKeeper ,那么本文将会是你进入 ZooKeeper 大门的垫脚砖。如果你已经接触过 ZooKeeper ,那么本文将带你回顾一下 ZooKeeper 的一些基础概念。**
最后,**本文只涉及 ZooKeeper 的一些概念,并不涉及 ZooKeeper 的使用以及 ZooKeeper 集群的搭建。** 网上有介绍 ZooKeeper 的使用以及搭建 ZooKeeper 集群的文章,大家有需要可以自行查阅。
## 一 什么是 ZooKeeper
### ZooKeeper 的由来
**下面这段内容摘自《从Paxos到Zookeeper 》第四章第一节的某段内容,推荐大家阅读以下:**
> Zookeeper最早起源于雅虎研究院的一个研究小组。在当时研究人员发现在雅虎内部很多大型系统基本都需要依赖一个类似的系统来进行分布式协调但是这些系统往往都存在分布式单点问题。所以**雅虎的开发人员就试图开发一个通用的无单点问题的分布式协调框架,以便让开发人员将精力集中在处理业务逻辑上。**
>
>关于“ZooKeeper”这个项目的名字其实也有一段趣闻。在立项初期考虑到之前内部很多项目都是使用动物的名字来命名的例如著名的Pig项目),雅虎的工程师希望给这个项目也取一个动物的名字。时任研究院的首席科学家RaghuRamakrishnan开玩笑地说“在这样下去我们这儿就变成动物园了”此话一出大家纷纷表示就叫动物园管理员吧一一一因为各个以动物命名的分布式组件放在一起**雅虎的整个分布式系统看上去就像一个大型的动物园了而Zookeeper正好要用来进行分布式环境的协调一一于是Zookeeper的名字也就由此诞生了。**
### 1.1 ZooKeeper 概览
ZooKeeper 是一个开源的分布式协调服务ZooKeeper框架最初是在“Yahoo!"上构建的,用于以简单而稳健的方式访问他们的应用程序。 后来Apache ZooKeeper成为HadoopHBase和其他分布式框架使用的有组织服务的标准。 例如Apache HBase使用ZooKeeper跟踪分布式数据的状态。**ZooKeeper 的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。**
> **原语:** 操作系统或计算机网络用语范畴。是由若干条指令组成的,用于完成一定功能的一个过程。具有不可分割性·即原语的执行必须是连续的,在执行过程中不允许被中断。
**ZooKeeper 是一个典型的分布式数据一致性解决方案,分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。**
**Zookeeper 一个最常用的使用场景就是用于担任服务生产者和服务消费者的注册中心(提供发布订阅服务)。** 服务生产者将自己提供的服务注册到Zookeeper中心服务的消费者在进行服务调用的时候先到Zookeeper中查找服务获取到服务生产者的详细信息之后再去调用服务生产者的内容与数据。如下图所示在 Dubbo架构中 Zookeeper 就担任了注册中心这一角色。
![Dubbo](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-9-10/35571782.jpg)
### 1.2 结合个人使用情况的讲一下 ZooKeeper
在我自己做过的项目中,主要使用到了 ZooKeeper 作为 Dubbo 的注册中心(Dubbo 官方推荐使用 ZooKeeper注册中心)。另外在搭建 solr 集群的时候,我使用 ZooKeeper 作为 solr 集群的管理工具。这时ZooKeeper 主要提供下面几个功能1、集群管理容错、负载均衡。2、配置文件的集中管理3、集群的入口。
我个人觉得在使用 ZooKeeper 的时候,最好是使用 集群版的 ZooKeeper 而不是单机版的。官网给出的架构图就描述的是一个集群版的 ZooKeeper 。通常 3 台服务器就可以构成一个 ZooKeeper 集群了。
**为什么最好使用奇数台服务器构成 ZooKeeper 集群?**
所谓的zookeeper容错是指当宕掉几个zookeeper服务器之后剩下的个数必须大于宕掉的个数的话整个zookeeper才依然可用。假如我们的集群中有n台zookeeper服务器那么也就是剩下的服务数必须大于n/2。先说一下结论2n和2n-1的容忍度是一样的都是n-1大家可以先自己仔细想一想这应该是一个很简单的数学问题了。
比如假如我们有3台那么最大允许宕掉1台zookeeper服务器如果我们有4台的的时候也同样只允许宕掉1台。
假如我们有5台那么最大允许宕掉2台zookeeper服务器如果我们有6台的的时候也同样只允许宕掉2台。
综上何必增加那一个不必要的zookeeper呢
## 二 关于 ZooKeeper 的一些重要概念
### 2.1 重要概念总结
- **ZooKeeper 本身就是一个分布式程序只要半数以上节点存活ZooKeeper 就能正常服务)。**
- **为了保证高可用,最好是以集群形态来部署 ZooKeeper这样只要集群中大部分机器是可用的能够容忍一定的机器故障那么 ZooKeeper 本身仍然是可用的。**
- **ZooKeeper 将数据保存在内存中,这也就保证了 高吞吐量和低延迟**但是内存限制了能够存储的容量不太大此限制也是保持znode中存储的数据量较小的进一步原因
- **ZooKeeper 是高性能的。 在“读”多于“写”的应用程序中尤其地高性能,因为“写”会导致所有的服务器间同步状态。**(“读”多于“写”是协调服务的典型场景。)
- **ZooKeeper有临时节点的概念。 当创建临时节点的客户端会话一直保持活动瞬时节点就一直存在。而当会话终结时瞬时节点被删除。持久节点是指一旦这个ZNode被创建了除非主动进行ZNode的移除操作否则这个ZNode将一直保存在Zookeeper上。**
- ZooKeeper 底层其实只提供了两个功能:①管理(存储、读取)用户程序提交的数据;②为用户程序提供数据节点监听服务。
**下面关于会话Session、 Znode、版本、Watcher、ACL概念的总结都在《从Paxos到Zookeeper 》第四章第一节以及第七章第八节有提到,感兴趣的可以看看!**
### 2.2 会话Session
Session 指的是 ZooKeeper 服务器与客户端会话。**在 ZooKeeper 中,一个客户端连接是指客户端和服务器之间的一个 TCP 长连接**。客户端启动的时候,首先会与服务器建立一个 TCP 连接,从第一次连接建立开始,客户端会话的生命周期也开始了。**通过这个连接客户端能够通过心跳检测与服务器保持有效的会话也能够向Zookeeper服务器发送请求并接受响应同时还能够通过该连接接收来自服务器的Watch事件通知。** Session的`sessionTimeout`值用来设置一个客户端会话的超时时间。当由于服务器压力太大、网络故障或是客户端主动断开连接等各种原因导致客户端连接断开时,**只要在`sessionTimeout`规定的时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话仍然有效。**
**在为客户端创建会话之前服务端首先会为每个客户端都分配一个sessionID。由于 sessionID 是 Zookeeper 会话的一个重要标识,许多与会话相关的运行机制都是基于这个 sessionID 的,因此,无论是哪台服务器为客户端分配的 sessionID都务必保证全局唯一。**
### 2.3 Znode
**在谈到分布式的时候,我们通常说的“节点"是指组成集群的每一台机器。然而在Zookeeper中“节点"分为两类第一类同样是指构成集群的机器我们称之为机器节点第二类则是指数据模型中的数据单元我们称之为数据节点一一ZNode。**
Zookeeper将所有数据存储在内存中数据模型是一棵树Znode Tree),由斜杠(/的进行分割的路径就是一个Znode例如/foo/path1。每个上都会保存自己的数据内容同时还会保存一系列属性信息。
**在Zookeeper中node可以分为持久节点和临时节点两类。所谓持久节点是指一旦这个ZNode被创建了除非主动进行ZNode的移除操作否则这个ZNode将一直保存在Zookeeper上。而临时节点就不一样了它的生命周期和客户端会话绑定一旦客户端会话失效那么这个客户端创建的所有临时节点都会被移除。** 另外ZooKeeper还允许用户为每个节点添加一个特殊的属性**SEQUENTIAL**.一旦节点被标记上这个属性那么在这个节点被创建的时候Zookeeper会自动在其节点名后面追加上一个整型数字这个整型数字是一个由父节点维护的自增数字。
### 2.4 版本
在前面我们已经提到Zookeeper 的每个 ZNode 上都会存储数据对应于每个ZNodeZookeeper 都会为其维护一个叫作 **Stat** 的数据结构Stat 中记录了这个 ZNode 的三个数据版本分别是version当前ZNode的版本、cversion当前ZNode子节点的版本和 aversion当前ZNode的ACL版本
### 2.5 Watcher
**Watcher事件监听器是Zookeeper中的一个很重要的特性。Zookeeper允许用户在指定节点上注册一些Watcher并且在一些特定事件触发的时候ZooKeeper服务端会将事件通知到感兴趣的客户端上去该机制是Zookeeper实现分布式协调服务的重要特性。**
### 2.6 ACL
Zookeeper采用ACLAccessControlLists策略来进行权限控制类似于 UNIX 文件系统的权限控制。Zookeeper 定义了如下5种权限。
![](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-9-10/27473480.jpg)
其中尤其需要注意的是CREATE和DELETE这两种权限都是针对子节点的权限控制。
## 三 ZooKeeper 特点
- **顺序一致性:** 从同一客户端发起的事务请求,最终将会严格地按照顺序被应用到 ZooKeeper 中去。
- **原子性:** 所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的,也就是说,要么整个集群中所有的机器都成功应用了某一个事务,要么都没有应用。
- **单一系统映像 ** 无论客户端连到哪一个 ZooKeeper 服务器上,其看到的服务端数据模型都是一致的。
- **可靠性:** 一旦一次更改请求被应用,更改的结果就会被持久化,直到被下一次更改覆盖。
## 四 ZooKeeper 设计目标
### 4.1 简单的数据模型
ZooKeeper 允许分布式进程通过共享的层次结构命名空间进行相互协调,这与标准文件系统类似。 名称空间由 ZooKeeper 中的数据寄存器组成 - 称为znode这些类似于文件和目录。 与为存储设计的典型文件系统不同ZooKeeper数据保存在内存中这意味着ZooKeeper可以实现高吞吐量和低延迟。
![](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-9-10/94251757.jpg)
### 4.2 可构建集群
**为了保证高可用,最好是以集群形态来部署 ZooKeeper这样只要集群中大部分机器是可用的能够容忍一定的机器故障那么zookeeper本身仍然是可用的。** 客户端在使用 ZooKeeper 时,需要知道集群机器列表,通过与集群中的某一台机器建立 TCP 连接来使用服务客户端使用这个TCP链接来发送请求、获取结果、获取监听事件以及发送心跳包。如果这个连接异常断开了客户端可以连接到另外的机器上。
**ZooKeeper 官方提供的架构图:**
![](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-9-10/68900686.jpg)
上图中每一个Server代表一个安装Zookeeper服务的服务器。组成 ZooKeeper 服务的服务器都会在内存中维护当前的服务器状态,并且每台服务器之间都互相保持着通信。集群间通过 Zab 协议Zookeeper Atomic Broadcast来保持数据的一致性。
### 4.3 顺序访问
**对于来自客户端的每个更新请求ZooKeeper 都会分配一个全局唯一的递增编号,这个编号反应了所有事务操作的先后顺序,应用程序可以使用 ZooKeeper 这个特性来实现更高层次的同步原语。** **这个编号也叫做时间戳——zxidZookeeper Transaction Id**
### 4.4 高性能
**ZooKeeper 是高性能的。 在“读”多于“写”的应用程序中尤其地高性能,因为“写”会导致所有的服务器间同步状态。(“读”多于“写”是协调服务的典型场景。)**
## 五 ZooKeeper 集群角色介绍
**最典型集群模式: Master/Slave 模式(主备模式)**。在这种模式中,通常 Master服务器作为主服务器提供写服务其他的 Slave 服务器从服务器通过异步复制的方式获取 Master 服务器最新的数据提供读服务。
但是,**在 ZooKeeper 中没有选择传统的 Master/Slave 概念而是引入了Leader、Follower 和 Observer 三种角色**。如下图所示
![](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-9-10/89602762.jpg)
**ZooKeeper 集群中的所有机器通过一个 Leader 选举过程来选定一台称为 “Leader” 的机器Leader 既可以为客户端提供写服务又能提供读服务。除了 Leader 外Follower 和 Observer 都只能提供读服务。Follower 和 Observer 唯一的区别在于 Observer 机器不参与 Leader 的选举过程,也不参与写操作的“过半写成功”策略,因此 Observer 机器可以在不影响写性能的情况下提升集群的读性能。**
![](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-9-13/91622395.jpg)
**当 Leader 服务器出现网络中断、崩溃退出与重启等异常情况时ZAB 协议就会进人恢复模式并选举产生新的Leader服务器。这个过程大致是这样的**
1. Leader election选举阶段节点在一开始都处于选举阶段只要有一个节点得到超半数节点的票数它就可以当选准 leader。
2. Discovery发现阶段在这个阶段followers 跟准 leader 进行通信,同步 followers 最近接收的事务提议。
3. Synchronization同步阶段:同步阶段主要是利用 leader 前一阶段获得的最新提议历史,同步集群中所有的副本。同步完成之后
准 leader 才会成为真正的 leader。
4. Broadcast广播阶段
到了这个阶段Zookeeper 集群才能正式对外提供事务服务,并且 leader 可以进行消息广播。同时如果有新的节点加入,还需要对新节点进行同步。
## 六 ZooKeeper &ZAB 协议&Paxos算法
### 6.1 ZAB 协议&Paxos算法
Paxos 算法应该可以说是 ZooKeeper 的灵魂了。但是ZooKeeper 并没有完全采用 Paxos算法 ,而是使用 ZAB 协议作为其保证数据一致性的核心算法。另外在ZooKeeper的官方文档中也指出ZAB协议并不像 Paxos 算法那样是一种通用的分布式一致性算法它是一种特别为Zookeeper设计的崩溃可恢复的原子消息广播算法。
### 6.2 ZAB 协议介绍
**ZABZooKeeper Atomic Broadcast 原子广播) 协议是为分布式协调服务 ZooKeeper 专门设计的一种支持崩溃恢复的原子广播协议。 在 ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性基于该协议ZooKeeper 实现了一种主备模式的系统架构来保持集群中各个副本之间的数据一致性。**
### 6.3 ZAB 协议两种基本的模式:崩溃恢复和消息广播
ZAB协议包括两种基本的模式分别是 **崩溃恢复和消息广播**。当整个服务框架在启动过程中,或是当 Leader 服务器出现网络中断、崩溃退出与重启等异常情况时ZAB 协议就会进人恢复模式并选举产生新的Leader服务器。当选举产生了新的 Leader 服务器同时集群中已经有过半的机器与该Leader服务器完成了状态同步之后ZAB协议就会退出恢复模式。其中**所谓的状态同步是指数据同步用来保证集群中存在过半的机器能够和Leader服务器的数据状态保持一致**。
**当集群中已经有过半的Follower服务器完成了和Leader服务器的状态同步那么整个服务框架就可以进人消息广播模式了。** 当一台同样遵守ZAB协议的服务器启动后加人到集群中时如果此时集群中已经存在一个Leader服务器在负责进行消息广播那么新加人的服务器就会自觉地进人数据恢复模式找到Leader所在的服务器并与其进行数据同步然后一起参与到消息广播流程中去。正如上文介绍中所说的ZooKeeper设计成只允许唯一的一个Leader服务器来进行事务请求的处理。Leader服务器在接收到客户端的事务请求后会生成对应的事务提案并发起一轮广播协议而如果集群中的其他机器接收到客户端的事务请求那么这些非Leader服务器会首先将这个事务请求转发给Leader服务器。
关于 **ZAB 协议&Paxos算法** 需要讲和理解的东西太多了,说实话,笔主到现在不太清楚这俩兄弟的具体原理和实现过程。推荐阅读下面两篇文章:
- [图解 Paxos 一致性协议](http://codemacro.com/2014/10/15/explain-poxos/)
- [Zookeeper ZAB 协议分析](https://dbaplus.cn/news-141-1875-1.html)
关于如何使用 zookeeper 实现分布式锁,可以查看下面这篇文章:
-
[10分钟看懂基于Zookeeper的分布式锁](https://blog.csdn.net/qiangcuo6087/article/details/79067136)
## 六 总结
通过阅读本文,想必大家已从 **①ZooKeeper的由来。** -> **②ZooKeeper 到底是什么 。**-> **③ ZooKeeper 的一些重要概念**会话Session、 Znode、版本、Watcher、ACL-> **④ZooKeeper 的特点。** -> **⑤ZooKeeper 的设计目标。**-> **⑥ ZooKeeper 集群角色介绍** Leader、Follower 和 Observer 三种角色)-> **⑦ZooKeeper &ZAB 协议&Paxos算法。** 这七点了解了 ZooKeeper 。
## 参考
- 《从Paxos到Zookeeper 》
- https://cwiki.apache.org/confluence/display/ZOOKEEPER/ProjectDescription
- https://cwiki.apache.org/confluence/display/ZOOKEEPER/Index
- https://www.cnblogs.com/raphael5200/p/5285583.html
- https://zhuanlan.zhihu.com/p/30024403