Zookeeper学习笔记

近来学习zookeeper,在B站看到个不错的学习视频。抄袭下笔记,视频链接在下面

【2021最新首发】这可能是B站讲的最好的 ZooKeeper 教程,(54P)全集从入门到精通,新清脱俗版!_哔哩哔哩_bilibili

1. Zookeeper简介

1.1 Zookeeper是什么

Zookeeper是一个分布式协调服务的开源框架。主要用来解决分布式集群中应用系统的一致性问题,例如怎样避免同时操作同一数据造成脏读的问题。

  • Zookeeper本质上是一个分布式的小文件存储系统,提供类似于文件系统的目录树方式的数据存储,并且可以对树中的节点进行有效管理。
  • Zookeeper提供个客户端监控存储在zk内部数据的功能,从而可以达到基于数据的集群管理。例如:统一命名服务(dubbo)、分布式配置管理(solr的配置集中管理)、分布式消息队列(sub/pub)、分布式锁、分布式协调等功能。

1.2 zookeeper的架构组成

Leader

  • Zookeeper集群工作的核心角色

  • 集群内部各个服务器的调度者

  • 事务请求(写操作)的唯一调度和处理者,保证集群事务处理的顺序性;对于create、setdata、delete等有写操作的请求,则需要统一转发给leader处理,leader需要决定编号、执行操作,这个过程称为一个事务。

Follower

  • 处理客户端非事务(读操作)请求
  • 转发事务请求给Leader
  • 参与集群Leader选举投票,2n-1台可以做集群投票。

此外,针对访问量比较大的Zookeeper集群,还可以新增观察者角色

Observer

  • 观察者角色,观察Zookeeper集群的最新状态并将这些状态同步过来,对于非事务请求可以进行独立处理,对于事务请求则会转发给Leader服务器进行处理。
  • 不会参数任何形式的投票,只提供非事务服务,通常用于不影响集群事务处理能力的前提下提升集群的非事务处理能力。增加了集群增加并发的读请求。

1.3 Zookeeper特点

  1. Zookeeper:一个领导者(Leader;老大),多个跟随者(follower;小弟)组成的集群。
  2. Leader负责进行投票的发起和决议,更新系统状态
  3. Follower用于接受客户请求并向客户端返回结果,在选举Leader过程中参与投票。
  4. 集群中只要有半数以上的节点存活,Zookeeper集群就能正常服务。
  5. 全局数据一致:每个server保存一份相同的数据副本,Client无论连接到哪个server,数据都是一致的。
  6. 更新请求顺序进行
  7. 数据更新原子性,一次数据更新要么成功,要么失败。

2. Zookeeper环境搭建

2.1 Zookeeper的搭建方式

Zookeeper安全方式有三种,单机模式和集群模式以及伪集群模式。

  • 单机模式:Zookeeper只运行在一台服务器上,适合测试环境。
  • 伪集群模式:就是在一台服务器上运行多个Zookeeper实例;
  • 集群模式:Zookeeper运行于一个集群上,适合生产环境,这个计算机集群被称为一个“集合体”

2.2 Zookeeper集群搭建

下载

到官网下载即可

解压压缩包

tar -xf zookeeper-3.4.13.tar.gz -C /opt

修改配置文件创建data与log目录

#更改为实际部署的目录,dataDir和dataLogDir建议分开在不同的磁盘下
dataDir=/opt/zookeeper-3.4.13/dataDir/zookeeper-1
dataLogDir=/opt/zookeeper-3.4.13/dataDir/zookeeper-1/log
#集群的IP和端口,2887为集群通讯端口,3887为选举端口
server1=10.1.10.1:2887:3887
server2=10.1.10.2:2887:3887
server3=10.1.10.3:2887:3887
#打开注释
#zk提供了自动清理事务日志和快照文件的功能,这个参数指定了清理的频率,单位是小时
autopurge.purgeInterval=1

添加myid配置

#在3台服务器上分别执行,其中1、2、3的myid和前面配置文件中server1、server2、server3相对应
cd /opt/zookeeper-3.4.13
echo 1 > /opt/zookeeper-3.4.13/dataDir/zookeeper-1/myid
echo 2 > /opt/zookeeper-3.4.13/dataDir/zookeeper-1/myid
echo 3 > /opt/zookeeper-3.4.13/dataDir/zookeeper-1/myid

依次启动zk实例

bin/zkServer.sh start

查看zk的启动状态

#发现会有一个zk成为了leader,其他两个为follower。
bin/zkServer.sh status

3. Zookeeper数据结构与监听机制

Zookeeper数据模型Znode

在Zookeeper中,数据信息被保存在一个个数据节点上,这些节点被称为znode。Znode是Zookeeper中最小的数据单位,在Znode下面又可以再挂载Znode,这样一层层下去就形成了一个层次化命名空间Znode树,我们称为ZNode Tree,它采用类似文件系统的层级树状结构进行管理,如下图所示:
image.png

在Zookeeper中,每个数据节点都是一个Znode,上图根目录下有两个节点,分别是app1和app2,其中app1下面又有三个子节点,所有Znode按层次化进行阻止,形成一棵树。Znode的节点路径标识方式和Unix文件系统路径非常相似,都是由一系列使用斜杠(/)进行分割的路径表示,开发人员可以向这个节点写入数据,也可以在这个节点下面创建子节点。

3.1 ZNode的类型

刚刚已经了解到,Zookeeper的znode tree是由一系列数据节点组成的,那接下来,我们就对数据节点做详细讲解。

Zookeeper节点类型可以分为三大类:

持久性节点(Persistent)

临时性节点(Ephemeral)

顺序性节点(Sequential)

在开发中创建节点的时候通过组合可以生成以下四种节点类型:持久节点、持久顺序节点、临时节点、临时顺序节点。不同类型的节点则会有不同的生命周期。

持久节点:是Zookeeper中最常见的一种节点类型,所谓持久节点,就是指节点被创建后会一直存在服务器,直到删除操作主动清除。

持久顺序节点:就是有顺序的持久节点,节点特性和持久节点是一样的,只是额外特性表现在顺序上。顺序特性实质是在创建节点的时候,会在节点名后面加上一个数字后缀,来表示其顺序。

临时节点:就是会自动清理掉的节点,它的生命周期和客户端会话绑定在一起,客户端会话结束后,节点会被删除掉。与持久性节点不同的是,临时节点不能创建子节点。

临时顺序节点:就是有顺序的临时节点,和持久顺序节点相同,在其创建的时候会在名字后面加上数字后缀。

事务ID

首先,先了解,事务是对物理和抽象的应用状态上的集合。往往在现在的概念中,狭义的事务通常指的是数据库事务,一般包含了一系列对数据库有序的读写操作,这些数据库事务具有所谓的ACID特性,即原子性(Atomic)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。

而在Zookeeper中,事务是指能够改变Zookeeper服务器状态的操作,我们也称之为事务操作或者更新操作,一般包括数据节点创建与删除、数据节点内容更新等操作。对于每个事务请求,Zookeeper都会为其分配一个全局唯一的事务ID,用ZXID来表示,通常是一个64位的数字。每个ZXID对应一次更新操作,从这些ZXID可以间接识别出Zookeeper处理这些更新操作请求的全局顺序。

3.2 ZNode的状态信息

[zk: localhost:2181(CONNECTED) 0] get /zookeeper

cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = -1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1

整个Znode节点内容包括两部分:节点数据内容和节点状态信息。数据内容是空,其他的属于状态信息。那么这些状态呢信息都有什么含义呢?

cZxid 就是Create ZXID,表示节点被创建时的事务ID
ctime 就是Create Time,表示节点的创建时间
mZxid 就是Modified ZXID,表示节点最后一次被修改的事务ID
mtime 就是Modified Time,表示节点最后一次被修改的时间
pZxid 表示该节点的子节点列表最后一个修改时的事务ID,只有子节点列表变更才会更新PZxid,子节点内容变更不会更新,
cversion 表示子节点的版本号
dataVersion 表示内容版本号
aclVersion 表示acl版本
ephemeralOwner 表示创建临时节点时的会话SessionID,如果是持久节点那么值为0.
dataLength 表示数据长度
numChildren 表示直系子节点数。

3.3 Watcher机制

Zookeeper使用Watcher机制实现分布式数据的发布/订阅功能

一个典型的发布/订阅模型系统定义了一种一对多的订阅关系,能够让多个订阅者同时监听某个主题对象,当这个主题对象自身状态发生改变时,会通知所有订阅者,使它们能够做出相应的处理。

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

整个Watcher注册与通知过程如图所示。

Zookeeper的Watcher机制主要包括客户端线程、客户端WatcherManager、Zookeeper服务器三部分。

具体工作流程为:

  • 客户端在向Zookeeper服务器注册的同时,会将Watcher对象存储在客户端的WatcherManager当中
  • 当Zookeeper服务器触发Watcher事件后,会向客户端发送通知
  • 客户端线程从WatcherManager中取出对应的Watcher对象来执行回调逻辑。

4. Zookeeper的基本使用

4.1 Zookeeper命令行操作

现在已经搭建起了一个能够正常运行的Zookeeper服务了,所以接下来,就是借助客户端来对Zookeeper的数据节点进行操作。

首先,进入到Zookeeper的bin目录。

通过zkCli进入zookeeper客户端命令行

./zkCli.sh #连接本地的zookeeper服务器
./zkCli.sh -server ip:port #连接指定的服务器

连接成功后,系统会输出Zookeeper的相关环境及配置信息等。输入help后,屏幕会输出可用的Zookeeper命令,如下所示:

[zk: 10.1.10.117:2181(CONNECTED) 3] help
ZooKeeper -server host:port cmd args
    stat path [watch]
    set path data [version]
    ls path [watch]
    delquota [-n|-b] path
    ls2 path [watch]
    setAcl path acl
    setquota -n|-b val path
    history 
    redo cmdno
    printwatches on|off
    delete path [version]
    sync path
    listquota path
    rmr path
    get path [watch]
    create [-s] [-e] path data acl
    addauth scheme auth
    quit 
    getAcl path
    close 
    connect host:port

创建节点

使用create命令,可以创建一个Zookeeper节点,如

#其中,-s或-e分别指定节点特性,顺序或临时节点,若不指定,则创建持久节点
create [-s] [-e] path data
  1. 创建顺序节点

    create -s /zk-test 123
    
  2. 创建临时节点

    #创建后退出客户端,然后再次连接验证该节点是否被删除
    create -e /zk-temp 123
    
  3. 创建永久节点

    create /zk-permanent 123
    

读取节点

与读取相关的命令有ls命令和get命令

ls命令可以列出Zookeeper指定节点下的所有子节点,但只能查看指定节点下的第一级的所有子节点;

#其中,path表示的是指定数据节点的节点路径
ls path

get命令可以获取Zookeeper指定节点的数据内容和属性信息。

get path
若获取根节点下的所有子节点,使用ls / 命令即可
[zk: 10.1.10.117:2181(CONNECTED) 0] ls /
[zookeeper, zk-test0000000020, zk-permanent]
若想获取/zk-permanent的数据内容和属性,可使用如下命令:get /zk-permanent
[zk: 10.1.10.117:2181(CONNECTED) 1] get /zk-permanent
123
cZxid = 0x34a
ctime = Mon Dec 27 22:49:21 CST 2021
mZxid = 0x34a
mtime = Mon Dec 27 22:49:21 CST 2021
pZxid = 0x34a
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
从上面的输出信息中,我们可以看到,第一行是节点的数据内容,其他几行则是创建该节点的事务ID(cZxid)、最后一次更新该节点的事务ID(mZxid)和最后一次更新该节点(mtime)的时间等属性信息。

更新节点

使用set命令,可以更新指定节点的数据内容,如下

set path data
其中,data就是要更新的新内容,version表示数据版本,在zookeeper中,节点的数据是有版本的概念的,这个参数用于指定本次更新操作是基于Znode的哪个数据版本进行的,如将/zk-permanent节点的数据更新为456,可以使用如下命令:`set /zk-permanent 456`
#留意mZxid的值
[zk: 10.1.10.117:2181(CONNECTED) 3] set /zk-permanent 456
cZxid = 0x34a
ctime = Mon Dec 27 22:49:21 CST 2021
mZxid = 0x34e
mtime = Mon Dec 27 23:00:24 CST 2021
pZxid = 0x34a
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
[zk: 10.1.10.117:2181(CONNECTED) 4] get /zk-permanent
456
...

删除节点

使用delete命令可以删除Zookeeper上的指定节点,用法如下:

delete path

其中version也表示数据版本,使用delete /zk-permanent 命令即可删除/zk-permanent节点。

[zk: 10.1.10.117:2181(CONNECTED) 5] delete /zk-permanent

要注意:若删除节点存在子节点,那么无法删除该节点,必须先删除子节点,再删除父节点。

4.2 使用命令行验证监听

可以使用Zookeeper自带的客户端能够验证zk的监听功能

监听节点变化

#只需要在后面加上watch参数即可
ls /  watch

#多开一个窗口,新建一个节点,查看zk是否发出通知
create /zk-test 123

WATCHER::

WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/

监听节点数据变化

get /zk-test watch

#多开一个窗口,更新节点的数据,查看zk是否发出通知
set /zk-test 456

WATCHER::

WatchedEvent state:SyncConnected type:NodeDataChanged path:/zk-test

自带的客户端之后接受一次监听的通知,要一直接收监听的通知需要不断地向zk注册,这时候可以使用一些开源的zk客户端工具来实现。

5. Zookeeper内部原理

5.1 Leader选举

选举机制

  • 半数机制:集群中半数以上的机器存活,集群可用。所以Zookeeper适合安装奇数台服务器。
  • Zookeeper虽然在配置文件中并没有指定Master和Slave。但是,Zookeeper工作时,是有一个节点为Leader,其他为Follower,Leader是通过集群内部的选举机制产生的。

集群首次启动

假设有五台服务器组成的Zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的。假设这些服务器依次启动,来看看会发生什么。

Zookeeper的选举机制

  1. 服务器1启动,此时只有它一台服务器启动了,它发出去的报文没有任何响应,所以它的选举状态一直都是LOOKING状态。
  2. 服务器2启动,它与最开始启动的服务器1进行通信,相互交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器胜出,但是由于没有达到半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1、2还是继续保持LOOKING状态。
  3. 服务器3启动,根据前面的理论分析,服务器3成为服务器1、2、3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的Leader。
  4. 服务器4启动,根据前面的分析,理论上服务器4应该是服务器1、2、3、4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能接受当小弟的命了。
  5. 服务器5启动,同4一样成为follower。

集群非首次启动

每个节点在选举时都会参考自身节点的zxid值(事务ID);优先选择zxid值大的节点成为Leader!!

5.2 ZABBIX一致性协议

1.分布式数据一致性问题

为什么会出现分布式数据一致性问题?

  • 将数据复制到分布式部署的多台机器中,可以消除单点故障,防止系统由于某台(些)机器宕机导致的不可用。
  • 通过负载均衡技术,能够让分布式在不同地方的数据副本全部都对外提供服务。有效提高系统性能。

在分布式系统中引入数据复制机制后,多台节点之间由于网络等原因很容易产生数据不一致的情况。

举例

当客户端Client1将系统中的一个值K1由V1更新为V2,但是客户端Client2读取的是一个还没有同步更新的副本,K1的值依然是V1,这就导致了数据的不一致性。其中,常见的就是主从数据库之间的复制延时问题。

2. ZAB协议

ZK就是分布式一致性问题的工业解决方案,paxos是其底层理论算法(晦涩难懂),其中zab、raft和众多开源算法是对paxos的工业级实现。ZK没有完全采用paxos算法,而是使用了一种称为Zookeeper Atom Broadcast(ZAB,Zookeeper原子消息广播协议)的协议作为其数据一致性的核心算法。

ZAB协议

ZAB协议是为分布式协调服务Zookeeper专门设计的一种支持崩溃恢复和原子广播协议。

主备模式保证一致性

ZK怎么处理集群中的数据?所有客户端写入数据都是写入Leader中,然后,由Leader复制到Follower中。ZAB会将服务器数据的状态变更以事务Proposa的形式广播到所有的副本进程上,ZAB协议能够保证了事务操作的一个全局的变更序号(ZXID)。

广播消息

ZAB协议的消息广播过程类似于二阶段提交过程,对于客户端发送的写请求,全部由Leader接收,Leader将请求封装成一个事务Proposa(提议),将其发送给所有Follower,如果收到超过半数反馈ACK,则执行Commit操作(先提交自己,再发送Commit给所有Follower)。

  1. 发送Proposal到Follower
  1. Leader接收Follower的ACK
  1. 超过半数ACK则Commit
不能正常反馈Follower恢复正常后会进入数据同步阶段最终与Leader保持一致。

细节

  • Leader接收带Client请求后,会将这个请求封装成一个事务,并给这个事务分配一个全局递增的唯一ID,称为事务ID(ZXID),ZAB协议要求保证事务的顺序,因此必须将每个事务按照ZXID进行先后排序然后处理。
  • ZK集群为了保证任何事务操作能够有序的顺序执行,只能是Leader服务器接收请求,即使是Follower服务器接收客户端的请求,也会转发到Leader服务器进行处理。

Leader崩溃问题

Leader宕机后,ZK集群无法正常工作,ZAB协议提供了一个高效且可靠的Leader选举算法。

Leader宕机后,被选举的新Leader需要解决的问题

  • ZAB协议确保那些已经在Leader提交的事务最终会被所有服务器提交
  • ZAB协议确保丢弃那些只在Leader提出/复制,但没有提交的事务。

基于上面的目的,ZAB协议设计了一个选举算法:能够确保已经被Leader提交的事务被集群接受,丢弃还没有提交的事务。

上面选举的关键点:保证选举出的新Leader拥有集群中所有节点最大编号(ZXID)的事务!!

6. Zookeeper应用实践

Zookeeper是一个典型的发布/订阅模式的分布式数据管理与协调框架,我们可以使用它来进行分布式数据的发布于订阅。另一方面,通过Zookeeper中丰富的数据节点类型进行交叉使用,配合Watcher事件通知机制,可以非常方便地构建一系列分布式应用中都会涉及的核心功能,如数据发布/订阅、命名服务、集群管理、Master选举、分布式锁和分布式队列等。那么接下来就针对这些典型的分布式应用场景来做下介绍

Zookeeper的两大特性

  1. 客户端如果对Zookeeper的数据节点注册Watcher监听,那么当该数据节点的内容或是其子节点列表发生变更时,Zookeeper服务器会向订阅的客户端发送变更通知。

  2. 对在Zookeeper上创建的临时节点,一旦客户端与服务器之间的会话失效,那么临时节点也会被自动删除

    利用这两大特性,可以实现集群机器存活监控系统,若监控系统在clustersercer节点上注册一个Watcher监听,那么但凡进行动态添加机器的操作,就会在/clusterServer节点下创建一个临时节点:/clusterServer/[hostname],这样,监控系统就能够实时监测机器的变动情况。

6.1 服务器的动态上下线监听

剩下的内容看视频学习吧,不好做笔记了。

你可能感兴趣的:(Zookeeper学习笔记)