文章目录

  • 1. zookeeper 简介
    • 1.1 什么是zookeeper
    • 1.2 zookeeper 发展历史
    • 1.3 zookeeper 典型应用场景
    • 1.4 zookeeper 提供的服务
    • 1.5 zookeeper的数据模型
    • 1.6 znode的分类
  • 2. Zookeeper架构
    • 2.1 整体架构
    • 2.2 session
    • 2.3 Quorum 模式
    • 2.4 数据一致性
  • 3. zookeeper的案例演示
    • 3.1 zookeeper 安装
    • 3.2 zookeeper启动
    • 3.3 zookeeper Client 交互式命令
    • 3.4 zookeeper 实现简单的分布式锁
    • 3.5 zookeeper实现master-worker架构
    • 3.6 zookeeper quorum集群模式
  • 4. 总结

通过本篇文章,你能够了解zookeeper的基本知识和应用场景,并且能够通过命令行完整体会到zookeeper的功能和基本应用场景。当然,因为作者水平有限,对分布式系统的理解多少有一些不足,希望大家不吝赐教。

本文通过如下几个方面介绍zookeeper基础:

  • zookeeper 的 发展历史 ,提供什么服务 以及 基本功能和应用场景
  • zookeeper 的整体架构
  • zookeeper 实现简单分布式锁 和 master-work架构,并演示zookeeper的集群模式

1. zookeeper 简介

希望通过zookeeper的发展历史,基本功能介绍以及应用场景来让大家对zookeeper有一个宏观的认识。

1.1 什么是zookeeper

一句话:zookeeper 是一个开源的分布式协同服务系统。说到系统而不是像raft那样的库,我们就能够理解 zookeeper拥有自己的client和server服务进程。

zookeeper的设计目标: 是将那一些复杂且容易出错的分布式系统服务封装起来,抽象出一个高效易用的原语集,并向用户提供简单的接口。

而比较有趣的是zookeeper 这个名字,认为zookeeper的工作性质就像是一个动物园管理员,用来协调整个动物园内的工作,让每一个动物都井井有条得处在自己的笼子里,游客(IO请求)能够安全得在动物园里游览并达到自己想去的位置而不受其他动物的影响。

1.2 zookeeper 发展历史

Zookeeper最早起源于雅虎研究院的一个研究小组。当时研究人员发现,在雅虎内部很多大型系统都依赖一个类似的系统来进行分布式协同,但是这一些系统都存在分布式单点问题

所以雅虎人员开发了一个通用的无单点问题的分布式协调框架,这就是ZK。在 zookeeper 被大量使用之后出现了如下著名的开源项目:

  1. Hadoop: 使用zookeeper 做namespace的高可用
  2. HBase: 保证集群只有一个Master;保存hbase:meta 表的位置,保存集群中的RegionServer列表
  3. Kafka: 集群成员管理,controller 节点选举

可见zookeeper还是能够提供足够的应用场景,且能够得到较多的开源项目的认可。
接下来可以看看zookeeper的典型场景:

1.3 zookeeper 典型应用场景

  • 配置管理(configuration management)
  • DNS 服务
  • 组成成员管理(group membership) – 经典的分布式数据库HBASE
  • 各种分布式锁(上一家公司参与的超融合存储项目 中即使用zookeeper来做一些集群锁的作用)

关于组成成员管理 和 分布式锁 后续的介绍中会为大家演示zookeeper原生接口如何实现简单的分布式锁的功能。当然,更深层次实现介绍还需要再摸索一番。

ps: zookeeper 适用于存储和协同相关的关键数据,不适合用于大量数据 存储。

1.4 zookeeper 提供的服务

这里简单说一下 zookeeper 提供什么样子的服务给到客户端。

  • Application 直接使用Zookeeper客户端库即可,目前主要是Java接口
  • Zookeeper的客户端库负责和Zookeeper集群中的server进行交互

1.5 zookeeper的数据模型

这里描述的并不是zookeeper的架构,仅仅是其数据存储相关的介绍。
我们知道在整个分布式系统的领域里,主流的两种数据存储方式是:树型 和 key-value型。

zookeeper这里选择树型模型(**data-tree)**的考虑是:

  • 便于表达数据之间的层次关系
  • 便于为不同的应用分配独立的命名空间

    如上图中 每一个节点叫做znode,都可以用来保存数据。
    同时每一个节点都有一个版本,这个版本是从0开始计数。

关于Zookeeper 提供的data-tree 数据模型有以下几点需要注意:

  1. 使用Unix 风格路径定位znode,例如 /A/A_1 表示A的子节点A_1
  2. 支持全量写入和读取,没有像普通文件系统那样支持部分写入和读取
  3. Data tree的所有API 都是wait-free的;正在调用的API不影响其他API的完成 即为wait-free
  4. Data tree 直接提供锁这样的分布式系统机制,但可以通过API来实现分布式协同机制

1.6 znode的分类

  1. 持久性Znode(Persistent):创建之后即使发生节点异常或集群宕机,znode 的信息也不会丢失
  2. 临时性Znode(Ephemeral): 节点宕机 或 在指定时间timeout 没有给zookeeper集群发消息, 这样的znode就会消失
  3. 持久顺序性Znode(Persistent_Sequential) znode 关联一个唯一的单调递增整数,这个整数是znode名字后缀,具备持久性。
  4. 临时顺序性Znode(Ephemeral_Sequential) 拥有顺序性的临时Znode 节点。

2. Zookeeper架构

以下的zookeeper架构仅仅是简要的介绍,并没有深入到各个机制的细节,后续文章会尝试进行探讨。

2.1 整体架构

应用使用zookeeper客户端(shell) 或者 zookeeper客户端库(java api) 使用zookeeper的基本服务。
zookeeper 客户端用来zookeeper集群进行交互。
实际的zookeeper集群可以有两种模式:standalone 模式 和 quorum 模式

  • standalone模式 即集群中只有一个节点作为server,一般的分布式系统不需要这样的模式,存在单点问题。适用于开发场景。
  • quorum 模式 即 集群有3个及以上的节点,通过quorum协议 为集群维护一个法定人数,只要集群存活的节点大于2/n+1(n表示节点数)个,则集群能够一直对外提供服务。

2.2 session

zookeeper 客户端和zookeeper集群建立链接时,会和集群中的某一个节点创建session。
关闭session有两种情况(客户端和集群断开链接):

  • 客户端可以主动关闭session
  • zookeeper集群节点没有在指定的timeout时间内收到客户端的消息的话,zookeeper节点也会关闭session。

如果zookeeper客户端库发现链接的zookeeper集群出错,会自动的和其他的zookeeper节点建立链接。如下图:

2.3 Quorum 模式

处于Quorum模式的集群包含多个节点,下图中的三个节点组成了一个zookeeper集群,其中绿色节点1的是leader节点,节点2和节点3是follower节点。leader节点可以处理读写请求,follower节点只能处理读请求,当写请求到达follower节点时会将写请求转发到leader节点。
写请求写入到leader之后,再由leader负责将数据同步到其他的follower节点。

2.4 数据一致性

我们知道分布式系统中的数据一致性主要是由于写 的顺序问题带来的一系列读/写相关的一致性问题。
zookeeper的设计目标是提供协调服务,并不会提供大量的数据存储,所以zookeeper 的主从架构则能够保证写请求的顺序性。

全局可线性化(Linearizable)写入: 大体的意思就是先到达leader的请求会被优先处理,leader决定写请求的执行顺序。
客户端FIFO顺序:来自给定客户端的请求按照发送顺序执行即可。

后续同样会通过 实际集群演示来 展示整个quorum 的zookeeper集群工作形态。

3. zookeeper的案例演示

以下将通过zookeeper的客户端 命令来演示zookeeper 的一些应用场景 以及 集群模式下的quorum机制。

3.1 zookeeper 安装

  • zookeeper的环境依赖是JDK7+
  • zookeeper源码包下载,我这里使用的是git:
    git clone https://github.com/apache/zookeeper.git
    git checkout branch-3.5.8 目前最新版本是3.6
  • 创建zoo.cfg
    可以直接拷贝 cp zookeeper/conf/zoo_example.cfg zookeeper/conf/zoo.cfg
    主要配置如下两个配置,

    # the directory where the snapshot is stored.
    # do not use /tmp for storage, /tmp here is just
    # example sakes.
    dataDir=/tmp/zookeeper
    # the port at which the clients will connect
    clientPort=2181
    ...
    
  • 导入zookeeper/bin目录到环境变量,方便使用相关的cli脚本,我放到了自己的~/.zshrc下,其他人可以放在自己的 ~/.bashrc
    export ZOOKEEPER_HOME="$HOME/IdeaProjects/zookeeper"
    export PATH="$ZOOKEEPER_HOME/bin/":$PATH
    

    这样能够在整个客户端的不同位置运行zookeeper的客户端脚本命令。

到此 整个zookeeper 已经安装完毕,当然这里还需要描述以下不同操作系统下的方式,以上步骤适用于所有类unix系统,包括mac os;Windows下只有最后一步不同,记得windows的shell rc文件和unix不同。

3.2 zookeeper启动

以下可以直接运行的命令是我之前已经将zookeeper/bin 目录放入到了path变量中,所以能够直接运行,具体步骤在上一节。

  • 启动server
    zkServer.sh start

    /usr/bin/java
    ZooKeeper JMX enabled by default
    Using config: /Users/zhanghuigui/IdeaProjects/zookeeper/bin/../conf/zoo.cfg
    Starting zookeeper ... STARTED
    

    可以在你自己的zookeeper的安装目录下有一个logs文件目录,用来保存服务进行运行的相关日志
    ~/IdeaProjects/zookeeper/logs ,其中IdeaProjects是我自己的目录,可以打开你自己的目录即可。
    可以看到日志中并没有异常报错。

    我们再去zookeeper的data目录看有哪一些数据:

    ╰─$ tree
    .
    ├── version-2
    │   └── snapshot.0 # zookeeper的快照文件
    └── zookeeper_server.pid #zookeeper server的进程id1 directory, 2 files
    
  • 启动 client
    zkCli.sh,能够看到已经运行的client,因为我们没有变更zoo.cfg端口号,所以client也会默认访问zoo.cfg的端口号建立连接。

    ...
    2020-11-21 14:56:40,635 [myid:localhost:2181] - INFO  [main-SendThread(localhost:2181):ClientCnxn$SendThread@1394] - Session establishment complete on server localhost/[0:0:0:0:0:0:0:1]:2181, sessionid = 0x100016e76ff0000, negotiated timeout = 30000WATCHER::WatchedEvent state:SyncConnected type:None path:null
    [zk: localhost:2181(CONNECTED) 0]
    

    这个时候能够进行交互命令,实现zookeeper的client和server的通信。

3.3 zookeeper Client 交互式命令

  • 输入h 可以看到很多交互式命令

    [zk: localhost:2181(CONNECTED) 0] h
    ZooKeeper -server host:port cmd argsaddauth scheme authcloseconfig [-c] [-w] [-s]connect host:portcreate [-s] [-e] [-c] [-t ttl] path [data] [acl]delete [-v version] pathdeleteall pathdelquota [-n|-b] pathget [-s] [-w] pathgetAcl [-s] path...
    
  • 输入ls -R / 所有访问znode的命令都需要加绝对路径,可以看到已经有一些根节点下的子节点存在了
    [zk: localhost:2181(CONNECTED) 2] ls -R /
    /
    /zookeeper
    /zookeeper/config
    /zookeeper/quota
    
  • create /app 创建第几个永久 znode
    [zk: localhost:2181(CONNECTED) 26] create /app1
    Created /app1
    [zk: localhost:2181(CONNECTED) 27] create /app2
    Created /app2
    [zk: localhost:2181(CONNECTED) 28] create /app1/app1_1
    Created /app1/app1_1
    [zk: localhost:2181(CONNECTED) 29] create /app1/app1_2
    Created /app1/app1_2
    

    再次查看对应的znode data tree信息

    [zk: localhost:2181(CONNECTED) 30] ls -R /
    /
    /app1
    /app2
    /zookeeper
    /app1/app1_1
    /app1/app1_2
    /zookeeper/config
    /zookeeper/quota
    
  • stat / 查看 根目录 znode元信息
    [zk: localhost:2181(CONNECTED) 31] stat /
    cZxid = 0x0
    ctime = Thu Jan 01 08:00:00 CST 1970 # 创建时间
    mZxid = 0x0
    mtime = Thu Jan 01 08:00:00 CST 1970 #修改时间
    pZxid = 0x13
    cversion = 17
    dataVersion = 0
    aclVersion = 0
    ephemeralOwner = 0x0
    dataLength = 0
    numChildren = 3 #子节点数量
    

3.4 zookeeper 实现简单的分布式锁

分布式锁的基本要求如下:

  • 锁被持有时其他 client无法访问 临界区的资源
  • 持有锁的进程/节点 宕机 ,锁需要被释放(防止死锁)

这是分布式锁的基本功能,通过zookeeper 显示如上基本功能:

使用两个Client来模拟一个集群中的两个节点,访问锁的情况。
基本步骤如下:

  • 节点一 持有锁 – 成功
  • 节点二 尝试持有锁 – 失败
  • 节点二 监控锁的使用情况
  • 节点一 异常退出,并释放锁
  • 节点二 感知到锁被释放,从而持有锁 – 成功

如下演示:

这里主要通过zookeeper的临时节点(Ephemeral) 来实现的,因为临时znode节点异常退出或者client和server无心跳,则znode数据会被清除掉,能够作为分布式锁的节点异常退出锁释放的条件。

不过这样的实现 后续需要深入探索以下zookeeper的一致性 和 这种场景下的性能问题,如果成百上千的客户端在等待这把锁,能否足够快得释放 以及 如果保证每次只有一个客户端拿到锁(如何保证多个客户端同时创建一个inode,而只能有一个客户端创建成功。。。,需要深入探讨一下zookeeper的一致性模型)。

3.5 zookeeper实现master-worker架构

master-worker 架构是一种应用比较广泛的分布式系统架构。
其中有一个master负责监控worker的状态,并负责为worker分配对应的任务。
有如下几个约束规则:

  • 在任何时刻,系统中只有一个master,不能同时出现两个mater或者多个master,这样整个系统的调度就乱掉了。
  • 系统中除了处于active状态的master,还有一个backup状态的mater,如果active master异常,则backup master能够立即接管,进行任务分配
  • master 实施监控worker状态,并能及时收到worker成员变化的通知。master收到worker成员变化的时候通常会重新进行任务分配。

比如HBase:
HMBase 是系统中的Master,HRegionServer 是系统中的worker。
HMBase 实时监控HBase Cluster中worker的变化,把Region分配给各个HRegionServer。系统中有一个HMBase 服务处于active,其他处于backup状态。

比如CEPH中的Cephfs:
同样多个mds提供cephfs元数据管理功能,每一时刻只有一个mds-active ,所有的元数据调度都由这个active的mds负责,其他备mds则提供active mds的接管服务。

那么如何在Zookeeper中实现master-worker架构呢?

  • 使用一个临时节点 /master表示master。master想要行使职能之前先要创建这个znode,创建成功,则进入active状态,否则进入backup状态,并使用watch机制监控/master,来及时得跟踪active master的状态。

    加入系统中现在有一个active master, 一个 backup master。如果active master异常,则它创建的/master就会被删除,并且被处于监听状态的backup master watch到,此时backup master通过创建自己的/master 临时节点来成为active master行使职能。

  • worker 通过在/workers 目录下创建子节点来加入集群

  • 处于active 状态的master 会通过watch 机制监听/works 下的znode列表,来感知集群worker的变化。


使用zookeeper实现 的基本功能master-worker架构 以及 data tree中对应的znode分布如上图,master通过一个znode节点表示,work则分布在一个大的workers父节点之下。

其中zookeeper master 和 backup master选举的演示功能如下:
主要是通过stat -w /master监控状态变化

zookeeper master监控 works成员列表变化的演示过程如下:
主要通过ls -w /works 监控节点成员变化

3.6 zookeeper quorum集群模式

之前的简单分布式锁以及master-work架构都是在同一台机器上通过不同的客户端实现的,接下来的集群模式如果大家想要了解且有多台服务器,玩一玩也不错。没有多台服务器也是可以的,按照如下配置即启动多个server进程组成quorum。

  • 配置文件
    之前单个server 只需要一个zoo.cfg,那我们配置集群模式肯定需要多个不同的zoo.cfg
    其中的dataDirclientPort需要配置成不同的值,三个zoo.cfg中的server.n 需要配置成一样的。

    server.1=127.0.0.1:7777:7778
    server.2=127.0.0.1:6666:6667
    server.3=127.0.0.1:5555:5556
    

    其中server.n中的ip是当前节点的ip,如果大家有各自的服务器,直接设置成服务器可通信的ip地址即可。
    ip之后的第一个端口号是:quorum 协议的通信端口,第二个端口号是leader选举的端口号
    如下配置

    除此之外,启动server之前,还需要先在每个server各自的dataDir目录下创建一个名称为myid的文件,内存分别是1,2,3,即在server.1的dataDir目录下创建一个myid文件,内容为1。其他的server依次都需要创建。

  • 启动过程需要通过前台启动server进程,并指定对应的zoo.cfg
    zkServer.sh start-foreground ./conf/zoo-node1.cfg,这样日志能够打印到客户端

    启动第一个server的时候,会有一些报错,因为只有一个节点,quorum无法满足法定人数。
    依次启动第二个server和第三个server,即能够发现对应的选举过程,启动第二个server的时候两个server中会有一个成为leader,此时启动client,即能够正常提供zookeepe服务。

    通过命令zkCli.sh -server 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183 ,指定对应的三个server ip和port即能够建立client和zookeeper集群的链接。

演示过程如下:

4. 总结

通过对zookeeper的简介,zookeeper的基本架构,zookeeper的一些简单应用的介绍,我们对zookeeper有了全面却很初步的理解,更多的细节:zookeeper 如何实现服务发现,zookeeper如何做到事件驱动,zookeeper的类似quorum模式zab协议的实现,以及如何在生产环境中通过java代码实现分布式锁,分布式队列,选举 这一系列更加底层更加易用的实现将在后续的学习中不断总结。

这是一个非常有代表性的分布式系统,涉及 分布式通信,分布式协议,分布式存储 ,复杂度相比于专门的分布式存储 系统低很多,更棒的是开源。每一个精妙的设计我们都能够看到其底层实现,细细品味。

一文入门 Zookeeper相关推荐

  1. 学习笔记:快速入门ZooKeeper技术

    学习视频:黑马程序员 ZooKeeper 视频教程,快速入门 ZooKeeper 技术 学习资料:黑马程序员 公众号提供的文档资料链接 | 提取码:dor4) 本文最后更新于 2022-04-25,若 ...

  2. gdb 调试_一文入门Linux下gdb调试(二)

    点击"蓝字"关注我吧 作者:良知犹存 转载授权以及围观:欢迎添加微信号:Conscience_Remains 总述     今天我们介绍一下core dump文件,Core dum ...

  3. linux gdb网络调试,一文入门Linux下gdb调试(二)

    本文转载自[微信公众号:羽林君,ID:Conscience_Remains] 总述 今天我们介绍一下core dump文件,Core dump叫做核心转储,它是进程运行时在突然崩溃的那一刻的一个内存快 ...

  4. 石油专业:一文入门机器学习,以测井岩性分类预测为例

    石油工程:一文入门机器学习,以测井岩性分类预测为例 1 前言 1.1 机器学习的相关背景 1.2 机器学习的八股文 2 模型实战 2.0 导入相关库 2.1 数据处理 2.1.1 数据读取 2.1.2 ...

  5. 转发 微博 Qzone 微信 一篇文章带你入门ZooKeeper实现原理!(超详细)

    转发 微博 Qzone 微信 一篇文章带你入门ZooKeeper实现原理!(超详细)

  6. 强化学习入门 : 一文入门强化学习 (Sarsa、Q learning、Monte-carlo learning、Deep-Q-Network等)

    最近博主在看强化学习的资料,找到这两个觉得特别适合入门,一个是"一文入门深度学习",一个是"莫烦PYTHON". 建议:看资料的时候可以多种资料一起参考,一边调 ...

  7. 一文入门HTML+CSS+JS(样例后续更新)

    一文入门HTML+CSS+JS(样例后续更新) 前言 HTML,CSS和JS的关系 HTML head元素 title link meta body元素 设置网页正文颜色与背景颜色 添加网页背景图片 ...

  8. 一文入门 Python 数据分析库 Pandas

    Pandas 通常用于快速简单的数据操作.聚合和可视化.在这篇文章中,我将概述如何学习这一工具的使用. Pandas 通常用于快速简单的数据操作.聚合和可视化.在这篇文章中,我将概述如何学习这一工具的 ...

  9. 一文入门 Kafka

    文末有重磅福利. 作者:ninetyhe,腾讯 CDG 后台开发工程师 温故而知新,反复学习优秀的框架,定有所获.因为工作原因,需要用到 Kafka 的特殊场景,周末再次阅读了 kafka 的资料,收 ...

最新文章

  1. Boost.SmartPtr 的快速 (CI) 测试
  2. python实现监控电脑打开网页_Python轻松实现动态网页爬虫(附详细源码)
  3. css html基础书,htmlcss基础知识汇总,新人必看!
  4. 调研报告|在线语音识别改进之 RNN-T 训练
  5. 给Ubuntu安装MacOS主题
  6. html的table的子节点,HTMLTableElement子节点并不如预期
  7. matlab 码表,0-254 ascii 码表
  8. 绘画教程:动漫人体肌肉的详细画法
  9. w7电脑蓝屏怎么解决_为你解答win7电脑蓝屏怎么办
  10. Java利用PdfBox实现Pdf转图片
  11. 计算机机器语言教程,机器语言.ppt
  12. 软考高级系统架构设计师:五大类安全服务
  13. New Concept English3 Lesson 2. Thirteen equals one【精讲学习笔记】
  14. mtklog结构及分析
  15. 用计算机汇编语言撰写,汇编语言是一种使用助记符号表示机器指令的计算机语言...
  16. 播放器地址抓取 php,从优酷土豆视频地址中获取swf播放器分享地址 - PHP示例代码...
  17. JAVA练习174-递归乘法
  18. Oracle如何清除一个用户下的所有表
  19. 短信接口防刷,限制IP的访问 部分笔记!
  20. 药检实验室如何规划设计

热门文章

  1. 导航条——收缩式导航菜单
  2. Atitit.java jna  调用c  c++ dll的原理与实践  总结  v2  q27
  3. 视觉惯性SLAM: VI ORB-SLAM
  4. oracle 10g undo 管理,Oracle 10g undo表空间管理
  5. html5标记汇总,HTML标记汇总(1)_HTML教程
  6. java 自定义注解 解析_java自定义注解
  7. 计算机设计原则,CISSP备考系列之计算机设计原则[10-39]
  8. python进程监控 supervisor_python supervisor进程监控工具的使用
  9. python中forward的参数_如何将关键字参数传递给preforward钩子使用的forward?
  10. shell脚本实现C程序日志分流和多Terminal显示