Zookeeper学习笔记-入门(1)-概述以及集群搭建

概述

Zookeeper 是一个开源的分布式的,为分布式框架提供协调服务的 Apache 项目。它的设计目标是将复杂且容易出错的分布式一致性服务封装起来,提供一系列简单易用的接口提供给用户使用。

在设计方面,Zookeeper上存储和管理了数据,观察者可以监听上面的某些数据。一旦这些数据的状态发生变化,Zookeeper就负责通知对应的观察者,触发对应的行为。可以理解为Zookeeper=文件系统+通知机制

Zookeeper的特点如下:

  1. 在集群构成方面,集群中存在一个Leader和多个Follower
  2. 只要集群中有半数以上的节点存活,Zookeeper就能够正常提供服务
  3. Zookeeper集群中数据保持全局的一致性,集群中每个服务器都保存了相同的数据副本。客户端无论连接到哪个服务器上,数据都是一致的
  4. 客户端也可以对Zookeeper中的数据进行写操作,并且更新请求会保持顺序执行,来自同一个Client的更新请求会按照发送顺序依次执行
  5. 数据更新保证原子性,一次数据更新要么成功要么失败
  6. 在一定时间范围内,Client能够读取到最新的数据

Zookeeper是一个典型的分布式数据一致性解决方案,分布式应用程序可以基于Zookeeper实现诸如数据发布/订阅、负载均衡、统一命名服务、统一配置管理、分布式协调/通知、统一集群管理、Master选举、分布式锁和分布式队列等功能。

  • 统一配置管理:集群中一般要求所有节点的配置信息是一致的,配置管理可以交由Zookeeper来管理
    • 将配置信息写入Zookeeper上的一个Node
    • 各个客户端服务器监听这个ZNode
    • 一旦ZNode中的数据被修改,Zookeeper将通知各个客户端服务器
  • 统一集群管理:在分布式环境下,实时掌握每个节点的状态是必要的,而Zookeeper可以实现实时监控节点状态变化
    • 节点将自己的信息写入Zookeeper上的一个ZNode
    • 监听这个ZNode可以获取集群的实时状态
  • 服务器动态上下线:客户端和服务器连接的情形中,客户端希望知道当前服务器的状态
    • 服务器向Zookeeper上注册,维护ZNode信息
    • 客户端监听对应的ZNode
    • 当服务器动态上下线,ZNode信息发生变化,Zookeeper也会通知对应的客户端
  • 负载均衡:在Zookeeper中记录每台服务器的访问数,让访问数最少的服务器去处理最新的客户端请求

重要概念

会话

会话Session,指的是客户端与Zookeeper服务器之间的连接。这里的客户端可以是Zookeeper提供的命令行工具,也可以是Java中的API等。

客户端启动的时候,首先会与服务器建立一个TCP连接,通过这个连接,客户端能够通过心跳检测与服务器保持有效的会话,也能够向ZooKeeper服务器发送请求并接受响应,同时还能够通过该连接接收来自服务器的Watch事件通知。而我们也可以设置客户端会话的超时时间等。

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

ZNode

Zookeeper中组织数据的模式类似于Unix文件系统,整体上可以看作是一棵树,每个节点称为一个ZNode。(注意这里的节点指的是Zookeeper中的数据存储节点,而不是集群中的服务器节点)每个ZNode默认存储1MB的数据,其中会维护一些属性,Zookeeper就根据这些数据来实现特定的功能。这种树形的结构使得每个ZNode都可以通过路径来唯一进行标识。Zookeeper的数据保存在内存中,这意味着Zookeeper可以实现高吞吐量和低延迟。

在Zookeeper中,ZNode主要可以分为持久节点和临时节点两类。持久节点指的是一旦这个ZNode被创建,除非主动进行ZNode的移除,否则它将会一直保存在Zookeeper上;而临时节点的生命周期与客户端会话绑定,当会话失效后,这个客户端创建的所有临时节点也都会被移除。

另外,Zookeeper还允许用户为每个节点添加一个特殊的属性SEQUENTIAL,一旦节点被标记上这个属性,那么再被创建的时候,Zookeeper会自动在其节点名称后面追加上一个整型数字,这个整型数字是由父节点维护的一个自增数字。

Zookeeper向我们提供对数据操作的API,操作的就是ZNode。包括ZNode的创建,数据修改,删除和监听等。

版本

ZooKeeper的每个Znode上都会都会存储数据,对应于每个Znode,ZooKeeper都会为其维护一个叫做Stat的数据结构,Stat中记录了这个Znode的三个数据版本,分别是version(当前Znode的版本)、cversion(当前Znode子节点的版本)和cversion(当前Znode的ACL版本)。

Watcher

Watcher,事件监听器,是Zookeeper中一个很重要的特性。Zookeeper允许用户在指定节点上注册一些Watcher。在一些特定事件触发的时候,例如ZNode状态改变的时候,Zookeeper服务端会将事件通知到对应的客户端上。这个机制也是Zookeeper实现分布式协调服务的重要特性。

ACL

ACL,AccessControlLists,是Zookeeper用来进行权限控制的策略,类似于UNIX文件系统的权限控制。Zookeeper中定义了如下5种权限:

  • create:创建子节点的权限
  • read:获取节点数据和子节点列表的权限
  • write:更新节点数据的权限
  • delete:删除子节点的权限
  • admin:设置节点ACL的权限

集群搭建

首先将压缩包解压到对应的目录下

1
tar -zxvf apache-zookeeper-3.5.7-bin.tar.gz -C /opt/module/

之后在对应目录下创建zkData目录,然后在zkData目录下创建一个名称为myid的文件,在myid文件种添加server对应的编号。例如这里hadoop102,我们给它编号为2。后续这个zkData目录会被配置为Zookeeper数据存储的目录。

1
2
3
4
5
6
mkdir zkData

cd zkData
vim myid

2

之后,将Zookeeper安装目录同步到其他集群中,并修改对应myid中的文件内容为3和4。

下一步需要进行配置文件的配置,将conf目录下的zoo_sample.cfg修改为zoo.cfg,然后修改其中的配置如下

1
2
3
4
5
6
7
# 修改数据存储路径配置
dataDir=/opt/module/zookeeper-3.5.7/zkData

# 增加集群配置
server.2=hadoop102:2888:3888
server.3=hadoop103:2888:3888
server.4=hadoop104:2888:3888

配置参数格式如server.A=B:C:D

  • A是一个数字,表示这个是第几号服务器,其中的内容对应myid文件中的内容。Zookeeper在启动的时候会读取配置的dataDir目录下的myid文件,拿到里面的数据与zoo.cfg中的配置信息进行对比,从而判断到底是哪个Server
  • B为服务器的地址
  • C为服务器Follower与集群中Leader服务器交换信息的端口
  • D是在Leader选举时服务器相互通信的端口

之后将配置文件进行同步即可。

之后,就可以启动集群了:

1
2
3
4
5
6
7
8
# 启动集群(在三台机器上分别启动)
bin/zkServer.sh start

# 查看集群状态
bin/zkServer.sh status

# 关闭集群
bin/zkServer.sh stop

类似地,我们也可以编写Zookeeper集群的启动停止脚本zk.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash
case $1 in
"start"){
for i in hadoop102 hadoop103 hadoop104
do
echo ---------- zookeeper $i 启动 ------------
ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh start"
done
};;
"stop"){
for i in hadoop102 hadoop103 hadoop104
do
echo ---------- zookeeper $i 停止 ------------
ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh stop"
done
};;
"status"){
for i in hadoop102 hadoop103 hadoop104
do
echo ---------- zookeeper $i 状态 ------------
ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh status"
done
};;
esac

选举机制

Zookeeper中的角色分为Leader和Follower。Leader是通过Zookeeper中的服务选举得来的。而Leader的选举又分为首次启动的选举和非首次启动的选举。

首先我们明确下面几个概念:

  • SID:服务器ID,用来唯一标识Zookeeper集群中的一台机器,与myid一致
  • ZXID:事务ID,用来标识一次服务器状态的变更。在某一时刻,集群中每台机器的ZXID值不一定完全一致,这和Zookeeper服务器对于客户端更新请求的处理逻辑有关
  • Epoch:每个Leader任期的代号

首次启动时,肯定会存在不同启动顺序。当服务器启动之后,会首先投自己一票,但是只有一票,不够半数以上,选举无法完成,则服务器状态保持Looking。随着集群其他机器启动,会再次发起选举,服务器在给自己投票之后不超过半数,则和其他机器交换投票信息,推举myid高的那个机器。如果仍然没有机器获得超过半数的票,则均保持Looking状态;如果有机器获得超过半数的票,则被推举为Leader。后续加入服务的机器,在已有Leader的情况下,直接以Follower角色加入。可以说,Leader的选举由启动顺序和myid共同决定

当Zookeeper集群中的一台服务器出现以下两种情况之一的时候,就会进入Leader选举阶段,分别是服务器初始化启动,以及服务器运行期间无法和Leader保持连接。

而当一台服务器进入Leader选举流程的时候,当前集群也可能会处于两种状态:分别是集群中已经存在Leader,以及集群中确实不存在Leader。

如果是第一种状况,集群中已经存在Leader,那么机器试图进行选举的时候,会被告知当前集群的Leader信息,那么当前服务器仅需要和Leader机器进行对接,然后进行状态同步即可

如果是第二种情况,集群中确实不存在Leader,那么则根据特定的规则进行Leader选举,主要就是利用前面说到的3个值的大小,优先级为Epoch>ZXID>SID,即Epoch大的直接胜出;Epoch相同,则事务ID大的胜出;事务ID相同,则服务器ID大d

参考文章

  1. ZooKeeper的各种各样及各样各种概念_叽里呱啦啦啦。的博客-CSDN博客

Zookeeper学习笔记-入门(1)-概述以及集群搭建
https://evernorif.github.io/2022/07/07/Zookeeper学习笔记-入门-1-概述以及集群搭建/
作者
EverNorif
发布于
2022年7月7日
许可协议