全网最祥,万字长文全面剖析ZooKeeper

一. ZooKeeper是什么

ZooKeeper由雅虎研究院开发,是Google Chubby的开源实现,后来托管到Apache,于2010年11月正式成为Apache的顶级项目。 
ZooKeeper是一个经典的分布式数据一致性解决方案,致力于为分布式应用提供一个高性能、高可用,且具有严格顺序访问控制能力的分布式协调服务。 
分布式应用程序可以基于ZooKeeper实现数据发布与订阅、负载均衡、命名服务、分布式协调与通知、集群管理、Leader选举、分布式锁、分布式队列等功能。

二. ZooKeeper目标

ZooKeeper致力于为分布式应用提供一个高性能、高可用,且具有严格顺序访问控制能力的分布式协调服务

2.1 高性能

ZooKeeper将全量数据存储在内存中,并直接服务于客户端的所有非事务请求,尤其适用于以读为主的应用场景

2.2 高可用

ZooKeeper一般以集群的方式对外提供服务,一般3 ~ 5台机器就可以组成一个可用的Zookeeper集群了,每台机器都会在内存中维护当前的服务器状态,并且每台机器之间都相互保持着通信。只要集群中超过一般的机器都能够正常工作,那么整个集群就能够正常对外服务

2.3 严格顺序访问

对于来自客户端的每个更新请求,ZooKeeper都会分配一个全局唯一的递增编号,这个编号反映了所有事务操作的先后顺序

三. ZooKeeper五大特性

ZooKeeper一般以集群的方式对外提供服务,一个集群包含多个节点,每个节点对应一台ZooKeeper服务器,所有的节点共同对外提供服务,整个集群环境对分布式数据一致性提供了全面的支持,具体包括以下五大特性:

3.1 顺序一致性

从同一个客户端发起的请求,最终将会严格按照其发送顺序进入ZooKeeper中

3.2 原子性

所有请求的响应结果在整个分布式集群环境中具备原子性,即要么整个集群中所有机器都成功的处理了某个请求,要么就都没有处理,绝对不会出现集群中一部分机器处理了某一个请求,而另一部分机器却没有处理的情况

3.3 单一性

无论客户端连接到ZooKeeper集群中哪个服务器,每个客户端所看到的服务端模型都是一致的,不可能出现两种不同的数据状态,因为ZooKeeper集群中每台服务器之间会进行数据同步

3.4 可靠性

一旦服务端数据的状态发送了变化,就会立即存储起来,除非此时有另一个请求对其进行了变更,否则数据一定是可靠的

3.5 实时性

当某个请求被成功处理后,ZooKeeper仅仅保证在一定的时间段内,客户端最终一定能从服务端上读取到最新的数据状态,即ZooKeeper保证数据的最终一致性

四. ZooKeeper集群角色

在分布式系统中,集群中每台机器都有自己的角色,ZooKeeper没有沿用传统的Master/Slave模式(主备模式),而是引入了Leader、Follower和Observer三种角色

4.1 Leader

集群通过一个Leader选举过程从所有的机器中选举一台机器作为”Leader”,Leader能为客户端提供读和写服务 
Leader服务器是整个集群工作机制的核心,主要工作:

  1. 事务请求的唯一调度者和处理者,保证集群事务处理的顺序性

  2. 集群内部各服务器的调度者

4.2 Follower

顾名思义,Follower是追随者,主要工作:

  1. 参与Leader选举投票

  2. 处理客户端非事务请求 - 即读服务

  3. 转发事务请求给Leader服务器

  4. 参与事务请求Proposal的投票

4.3 Observer

Observer是ZooKeeper自3.3.0版本开始引入的一个全新的服务器角色,充当一个观察者角色,工作原理和Follower基本是一致的,和Follower唯一的区别是Observer不参与任何形式的投票

  1. 处理客户端非事务请求 - 即读服务

  2. 转发事务请求给Leader服务器

  3. 不参与Leader选举投票

  4. 参与事务请求Proposal的投票

所以Observer可以在不影响写性能的情况下提升集群的读性能

五. 原子广播协议 - Zab

ZooKeeper并非采用经典的分布式一致性协议 - Paxos,而是参考了Paxos设计了一种更加轻量级的支持崩溃可恢复的原子广播协议-Zab(ZooKeeper Atomic Broadcast)。 
ZAB协议分为两个阶段 - Leader Election(领导选举)和Atomic Broadcast(原子广播)

5.1 领导选举 - Leader Election

当集群启动时,会选举一台节点为Leader,而其他节点为Follower,当Leader节点出现网络中断、崩溃退出与重启等异常情况,ZAB会进入恢复模式并选举产生新的Leader服务器,当集群中已有过半机器与该Leader服务器完成数据状态同步,退出恢复模式

5.2 原子广播 - Atomic Broadcast

当领导选举完成后,就进入原子广播阶段。此时集群中已存在一个Leader服务器在进行消息广播,当一台同样遵循ZAB协议的服务器启动后加入到集群中,新加的服务器会自动进入数据恢复阶段

六. 事务请求

在ZooKeeper中,事务是指能够改变ZooKeeper服务器状态的请求,一般指创建节点、更新数据、删除节点以及创建会话操作

6.1 事务转发

为了保证事务请求被顺序执行,从而确保ZooKeeper集群的数据一致性,所有的事务请求必须由Leader服务器处理,ZooKeeper实现了非常特别的事务请求转发机制: 
所有非Leader服务器如果接收到来自客户端的事务请求,必须将其转发给Leader服务器来处理

6.2 事务ID - ZXID

在分布式系统中,事务请求可能存在依赖关系,如变更C需要依赖变更A和变更B,这样就要求ZAB协议能够保证如果一个状态变更成功被处理了,那么其所有依赖的状态变更都应该已经提前被处理掉了。 
在ZooKeeper中对每一个事务请求,都会为其分配一个全局唯一的事务ID,使用ZXID表示,通常是一个64位的数字。每一个ZXID对应一次事务,从这些ZXID可以间接识别出ZooKeeper处理这些事务请求的全局顺序

七. 数据节点 - ZNode

ZooKeeper内部拥有一个树状的内存模型,类似文件系统,只是在ZooKeeper中将这些目录与文件系统统称为ZNode,ZNode是ZooKeeper中数据的最小单元,每个ZNode上可以保存数据,还可以挂载子节点,因此构成了一个层次化的命名空间

7.1 节点路径

ZooKeeper中使用斜杠(/)分割的路径表示ZNode路径,斜杠(/)表示根节点

7.2 节点特性

在ZooKeeper中,每个数据节点ZNode都是有生命周期的,其生命周期的长短取决于ZNode的节点类型

7.3 权限控制 - ACL

为了有效保障ZooKeeper中数据的安全,避免因误操作而带来数据随意变更导致分布式系统异常,ZooKeeper提供了一套完善的ACL(Access Contro List)权限控制机制来保障数据的安全。 
可以从三个方面理解ACL机制,分别是:权限模式(Scheme)、授权对象(ID)和权限(Permission),通常使用”scheme:id:permission”来标识一个有效的ACL信息

7.4 节点状态信息

每个数据节点ZNode除了存储数据内容外,还存储了数据节点本身的一些状态信息

7.5 节点版本

ZooKeeper为数据节点引入版本的概念,对个数据节点都具有三种类型的版本信息,对数据节点的任何更新操作都会引起版本号的变化

在分布式系统中,在运行过程中往往需要保证数据访问的排他性。Java并发中是实现了对CAS的指令支持,即对于值V,每次更新前都会比对其值是否是预期值A,只有符合预期,才会将V原子化的更新到新值B 
而ZooKeeper每个节点都有数据版本的概念,在调用更新操作的时候,先从请求中获取当前请求的版本version,同时获取服务器上该数据最新版本currentVersion,如果无法匹配,就无法更新成功,这样可以有效避免一些分布式更新的并发问题

八. Watcher - 数据变更的通知

在ZooKeeper中,引入Watcher机制来实现分布式数据的发布/订阅功能。ZooKeeper允许客户端向服务器注册一个Watcher监听,当服务器的一些指定事件触发了这个Watcher,那么就会向指定客户端发送一个事件通知来实现分布式的通知功能

Watcher机制为以下三个过程:

8.1 客户端注册Watcher

在创建一个ZooKeeper客户端对象实例时,可以向构造方法中传入一个Watcher,这个Watcher将作为整个ZooKeeper会话期间的默认Watcher,一致保存在客户端,并向ZooKeeper服务器注册Watcher 
客户端并不会把真实的Watcher对象传递到服务器,仅仅只是在客户端请求中使用boolean类型属性进行标记,降低网络开销和服务器内存开销

8.2 服务端处理Watcher

服务端执行数据变更,当Watcher监听的对应数据节点的数据内容发生变更,如果找到对应的Watcher,会将其提取出来,同时从管理中将其删除(说明Watcher在服务端是一次性的,即触发一次就失效了),触发Watcher,向客户端发送通知

8.3 客户端回调Watcher

客户端获取通知,识别出事件类型,从相应的Watcher存储中去除对应的Watcher(说明客户端也是一次性的,即一旦触发就会失效)

8.4 总结

  1. 一致性:无论是客户端还是服务器,一旦一个Watcher被处罚,ZooKeeper都会将其从相应的存储中移除,因此开发人员在Watcher使用上要反复注册,这样可以有效减轻服务器压力

  2. 客户端串行执行:客户端Watcher回调的过程是一个串行同步的过程,这保证了顺序

  3. 轻量:客户端并不会把真实的Watcher对象传递到服务器,仅仅只是在客户端请求中使用boolean类型属性进行标记,降低网络开销和服务器内存开销

九. Session - 会话

Session是指客户端连接 - 客户端和服务器之间的一个TCP长连接

9.1 会话状态

会话在整个生命周期中,会在不同的会话转态之间进行切换

9.2 Session属性

Session是ZooKeeper中的会话实体,代表了一个客户端会话,其包含4个属性:

9.3 心跳检测

为了保证客户端会话的有效性,客户端会在会话超时时间范围内向服务器发送PING请求来保持会话的有效性,即心跳检测。 
服务器接收到客户端的这个心跳检测,就会重新激活对应的客户端会话

9.4 会话清理

服务器的超级检查线程会在指定时间点进行检查,整理出一些已经过期的会话后,就要开始进行会话清理了:

  1. 关闭会话

  2. 清理相关的临时节点

9.5 重连

当客户端和服务器之间网络连接断开,客户端会自动进行反复的重连,直到最终成功连接上ZooKeeper集群中的一台机器

  1. 在会话超时时间内重新连接上,被视为重连成功

  2. 在会话超时时间外重新连接上,此时服务器已经进行了会话清理,但客户端不知道会话已经失效,重新连接服务器会告诉客户端会话已失效,被视为非法会话

在此阶段,我们已经充分了解了什么是Zookeeper了,那么我们接下来用它能做什么,单机模式的安装,以及它的使用来为大家做详细介绍。

Zookeeper能做什么

zookeeper功能非常强大,可以实现诸如分布式应用配置管理、统一命名服务、状态同步服务、集群管理等功能,我们这里拿比较简单的分布式应用配置管理为例来说明。

假设我们的程序是分布式部署在多台机器上,如果我们要改变程序的配置文件,需要逐台机器去修改,非常麻烦,现在把这些配置全部放到zookeeper上去,保存在 zookeeper 的某个目录节点中,然后所有相关应用程序对这个目录节点进行监听,一旦配置信息发生变化,每个应用程序就会收到 zookeeper 的通知,然后从 zookeeper 获取新的配置信息应用到系统中。

如上,你大致应该了解zookeeper是个什么东西,大概能做些什么了,我们马上来学习下zookeeper的安装及使用,并开发一个小程序来实现zookeeper这个分布式配置管理的功能。

Zookeeper单机模式安装

Step1:配置JAVA环境,检验环境:java -version

Step2:下载并解压zookeeper

# cd /usr/local# wget http://mirror.bit.edu.cn/apache/zookeeper/stable/zookeeper-3.4.12.tar.gz# tar -zxvf zookeeper-3.4.12.tar.gz# cd zookeeper-3.4.12

Step3:重命名配置文件zoo_sample.cfg

# cp conf/zoo_sample.cfg conf/zoo.cfg

Step4:启动zookeeper

# bin/zkServer.sh start

Step5:检测是否成功启动,用zookeeper客户端连接下服务端

# bin/zkCli.sh

Zookeeper使用

使用客户端命令操作zookeeper

1、使用 ls 命令来查看当前 ZooKeeper 中所包含的内容

2、创建一个新的 znode ,使用 create /zkPro myData

3、再次使用 ls 命令来查看现在 zookeeper 中所包含的内容:

4、下面我们运行 get 命令来确认第二步中所创建的 znode 是否包含我们所创建的字符串:

5、下面我们通过 set 命令来对 zk 所关联的字符串进行设置:

6、下面我们将刚才创建的 znode 删除

使用Java API操作zookeeper

使用Java API操作zookeeper需要引用下面的包

下面我们来实现上面说的分布式配置中心:

1、在zookeeper里增加一个目录节点,并且把配置信息存储在里面

2、启动两个zookeeper客户端程序,代码如下所示

import java.util.concurrent.CountDownLatch;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.Watcher.Event.EventType;import org.apache.zookeeper.Watcher.Event.KeeperState;import org.apache.zookeeper.ZooKeeper;import org.apache.zookeeper.data.Stat; /** * 分布式配置中心demo * @author  * */public class ZooKeeperProSync implements Watcher {     private static CountDownLatch connectedSemaphore = new CountDownLatch(1);    private static ZooKeeper zk = null;    private static Stat stat = new Stat();     public static void main(String[] args) throws Exception {        //zookeeper配置数据存放路径        String path = "/username";        //连接zookeeper并且注册一个默认的监听器        zk = new ZooKeeper("192.168.31.100:2181", 5000, //                new ZooKeeperProSync());        //等待zk连接成功的通知        connectedSemaphore.await();        //获取path目录节点的配置数据,并注册默认的监听器        System.out.println(new String(zk.getData(path, true, stat)));         Thread.sleep(Integer.MAX_VALUE);    }     public void process(WatchedEvent event) {        if (KeeperState.SyncConnected == event.getState()) {  //zk连接成功通知事件            if (EventType.None == event.getType() && null == event.getPath()) {                connectedSemaphore.countDown();            } else if (event.getType() == EventType.NodeDataChanged) {  //zk目录节点数据变化通知事件                try {                    System.out.println("配置已修改,新值为:" + new String(zk.getData(event.getPath(), true, stat)));                } catch (Exception e) {                }            }        }    }}

两个程序启动后都正确的读取到了zookeeper的/username目录节点下的数据'qingfeng'

3、我们在zookeeper里修改下目录节点/username下的数据

修改完成后,我们看见两个程序后台都及时收到了他们监听的目录节点数据变更后的值,如下所示

Zookeeper集群模式安装

本例搭建的是伪集群模式,即一台机器上启动三个zookeeper实例组成集群,真正的集群模式无非就是实例IP地址不同,搭建方法没有区别

Step1:配置JAVA环境,检验环境:java -version

Step2:下载并解压zookeeper

# cd /usr/local# wget http://mirror.bit.edu.cn/apache/zookeeper/stable/zookeeper-3.4.12.tar.gz# tar -zxvf zookeeper-3.4.12.tar.gz# cd zookeeper-3.4.12

Step3:重命名 zoo_sample.cfg文件

# cp conf/zoo_sample.cfg conf/zoo-1.cfg

Step4:修改配置文件zoo-1.cfg,原配置文件里有的,修改成下面的值,没有的则加上

# vim conf/zoo-1.cfgdataDir=/tmp/zookeeper-1clientPort=2181server.1=127.0.0.1:2888:3888server.2=127.0.0.1:2889:3889server.3=127.0.0.1:2890:3890

配置说明

  • tickTime:这个时间是作为 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。

  • initLimit:这个配置项是用来配置 Zookeeper 接受客户端(这里所说的客户端不是用户连接 Zookeeper 服务器的客户端,而是 Zookeeper 服务器集群中连接到 Leader 的 Follower 服务器)初始化连接时最长能忍受多少个心跳时间间隔数。当已经超过 10个心跳的时间(也就是 tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 10*2000=20 秒

  • syncLimit:这个配置项标识 Leader 与 Follower 之间发送消息,请求和应答时间长度,最长不能超过多少个 tickTime 的时间长度,总的时间长度就是 5*2000=10秒

  • dataDir:顾名思义就是 Zookeeper 保存数据的目录,默认情况下,Zookeeper 将写数据的日志文件也保存在这个目录里。

  • clientPort:这个端口就是客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。

  • server.A=B:C:D:其中 A 是一个数字,表示这个是第几号服务器;B 是这个服务器的 ip 地址;C 表示的是这个服务器与集群中的 Leader 服务器交换信息的端口;D 表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,而这个端口就是用来执行选举时服务器相互通信的端口。如果是伪集群的配置方式,由于 B 都是一样,所以不同的 Zookeeper 实例通信端口号不能一样,所以要给它们分配不同的端口号。

Step4:再从zoo-1.cfg复制两个配置文件zoo-2.cfg和zoo-3.cfg,只需修改dataDir和clientPort不同即可

# cp conf/zoo-1.cfg conf/zoo-2.cfg# cp conf/zoo-1.cfg conf/zoo-3.cfg# vim conf/zoo-2.cfgdataDir=/tmp/zookeeper-2clientPort=2182# vim conf/zoo-2.cfgdataDir=/tmp/zookeeper-3clientPort=2183

Step5:标识Server ID

创建三个文件夹/tmp/zookeeper-1,/tmp/zookeeper-2,/tmp/zookeeper-2,在每个目录中创建文件myid 文件,写入当前实例的server id,即1.2.3

# cd /tmp/zookeeper-1# vim myid1# cd /tmp/zookeeper-2# vim myid2# cd /tmp/zookeeper-3# vim myid3

Step6:启动三个zookeeper实例

# bin/zkServer.sh start conf/zoo-1.cfg# bin/zkServer.sh start conf/zoo-2.cfg# bin/zkServer.sh start conf/zoo-3.cfg

Step7:检测集群状态,也可以直接用命令“zkCli.sh -server IP:PORT”连接zookeeper服务端检测

至此,我们对zookeeper就算有了一个入门的了解,当然zookeeper远比我们这里描述的功能多,比如用zookeeper实现集群管理,分布式锁,分布式队列,zookeeper集群leader选举等等。

想必大家对zookeeper有了一个了解吧!如果有更深层次的理解,欢迎在评论区和我讨论讨论!

(0)

相关推荐

  • Zookeeper

    Zookeeper

  • Zookeeper工作过程详解

    一.Zookeeper工作机制 分布式和集中式系统相比,有很多优势,比如更强的计算能力,存储能力,避免单点故障等问题.但是由于在分布式部署的方式遇到网络故障等问题的时候怎么保证各个节点数据的一致性和可 ...

  • 万字详解 Zookeeper 的五个核心知识点

    Java高级架构师2021-01-15 15:20:57 1 ZooKeeper简介 ZooKeeper 是一个开源的分布式协调框架,它的定位是为分布式应用提供一致性服务,是整个大数据体系的管理员.Z ...

  • Zookeeper简介与集群搭建

    Zookeeper简介 Zookeeper是一个高效的分布式协调服务,可以提供配置信息管理.命名.分布式同步.集群管理.数据库切换等服务.它不适合用来存储大量信息,可以用来存储一些配置.发布与订阅等少 ...

  • 便捷搭建 Zookeeper 服务器的方法

    极客挖掘机 今天 什么是 ZooKeeper ZooKeeper 是 Apache 的一个顶级项目,为分布式应用提供高效.高可用的分布式协调服务,提供了诸如数据发布/订阅.负载均衡.命名服务.分布式协 ...

  • 你真的懂Zookeeper么?

    谈起Zookeeper可能很多开发者都说,这个很简单啊,我在Dubbo和Kafka中经常用,没什么难的,但是用了这么久,你真的懂Zookeeper么? 4月6日的开课吧<HelloWorld公开 ...

  • 面试:Zookeeper常见11个连环炮

    获取:10万字的面试小抄 面试的时候,面试官只要看到你简历的上写的有Zookeeper(熟悉.掌握)之类,那你至少要准备接下来的11连问. NO1:说说zookeeper是什么? ZooKeeper是 ...

  • 深入浅出Zookeeper

    ZooKeeper 是一个分布式协调服务 ,由 Apache 进行维护. ZooKeeper 可以视为一个高可用的文件系统. ZooKeeper 可以用于发布/订阅.负载均衡.命令服务.分布式协调/通 ...

  • 万字长文深度剖析面向对象的javascript

    简介 本将会深入讲解面向对象在javascript中的应用,并详细介绍三种对象的生成方式:构造函数,原型链,类. 什么是对象 虽然说程序员不缺对象,随时随地都可以new一个出来,但是在程序的世界中,对 ...

  • 上线10天iOS流水破亿,万字长文剖析《最强蜗牛》

    据了解,背后研发商青瓷游戏曾出品过<不可思议迷宫>.<阿瑞斯病毒>等精品,尤其是<不可思议迷宫>,月流水平均超千万,在2017.2018年为大股东吉比特创造不少营收 ...

  • 误诊率高达70%的疾病,患者能死里逃生吗?1万字长文,惊醒了许多人!

    很快,凌晨1点,接到急诊科老马医生的电话,说有个60岁的男性病人,呼吸困难.血氧不是很好,可能需气管插管上呼吸机,问ICU有没有床位. 正好是华哥值班,华哥刚忙完病人躺下休息了半个小时,这下又接到老马 ...

  • 万字长文:如何学习商业分析(PPT 说明)

    概述商业分析 商业分析是什么呢?摘录一段百科:商业分析指的是对方案进行经济效益分析,从财务上进一步判断它是否符合企业目标.如果符合,产品概念就可进入产品研制阶段了.包括审视预计的销售额.成本和利润是否 ...

  • 万字长文:新经销对行业&渠道认知的10个理论基础

    新经销一直以来对快速消费品行业渠道领域不断做深度的解读,这种解读背后,是有一定的认知模型做为理论指导的,这也是新经销指导内部编辑同事对行业认识的一个基础内容,今天也把这些基础框架知识,整理成一篇文章, ...

  • VC万字长文透露:当下最大的创业机会

    整理|韩希言 当下,最新的创业机会是什么?它的底层驱动力又是怎样?我们今天来谈谈这个话题. 张昊,星瀚资本董事总经理,拥有超10年国际金融机构工作经验,主导投资并负责管理的案例包括旷盛动漫.领驭国际. ...

  • 国产化率仅12%!万字长文看懂半导体关键原料电子特气

    原标题:国产化率仅12%!万字长文看懂半导体关键原料电子特气 来源:芯智讯 近年来,随着国家的对于集成电路产业的重视以及资本的支持,国内的集成电路产业发展迅速,但是与国外仍有不小的差距,特别是在上游的 ...

  • 万字长文解读:休闲食品,千亿赛道,挖掘创业新机遇

    我们有幸身处在这样一个时代洪流中. 往前看,我们已站在互联网最高点,有腾讯.滴滴.今日头条这样一大批移动独角兽傲立在浪潮之巅. 在风光的另一面,却伴随着的是大量传统品牌开始逐渐走向衰落.危机甚至是死亡 ...

  • 三万字长文系统讲解主动型基金投资体系(1):投资历史

    微博/雪球:小鱼量化 前些日子发布了一篇文章重磅发布:几年的投资经验总结尽在此文,总结介绍了我涉猎的所有投资品种和投资方法,做了一张超长的思维导图,大家以在公众号回复"思维导图"下 ...