超全zookeeper知识点与实战

Posted Leokadia Rothschild

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了超全zookeeper知识点与实战相关的知识,希望对你有一定的参考价值。

第1章 Zookeeper
1.1 概述
Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目。

配合其他服务器,
文件系统——存储各种服务器上线信息
通知机制——客户端跟zookeeper打招呼
1.2 特点

1)Zookeeper:一个领导者(Leader),多个跟随者(Follower)组成的集群。
2)集群中只要有半数以上节点存活,Zookeeper集群就能正常服务。所以Zookeeper适合安装奇数台服务器。 (如果偶数就浪费了一台集群)
3)全局数据一致:每个Server保存一份相同的数据副本,Client无论连接到哪个Server,数据都是一致的。
4)更新请求顺序执行,来自同一个Client的更新请求按其发送顺序依次执行。
5)数据更新原子性,一次数据更新要么成功,要么失败。
(封装成一个大的事务,要么整体成功,要么整体失败)
6)实时性,在一定时间范围内,Client能读到最新数据。
(同步数据,速度非常快,因为zookeeper里面的数据非常小)
1.3 数据结构
数据结构
ZooKeeper数据模型的结构与Unix文件系统很类似,整体上可以看作是一棵树,每个节点称做一个ZNode。每一个ZNode默认能够存储1MB的数据,每个ZNode都可以通过其路径唯一标识。

存储的数据量比较小,存储的内容有限
1.4 应用场景
提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等。

统一命名服务
在分布式环境下,经常需要对应用/服务进行统一命名,便于识别。
例如:IP不容易记住,而域名容易记住。

统一配置管理
1)分布式环境下,配置文件同步非常常见。
(1)一般要求一个集群中,所有节点的配置信息是一致的,比如 Kafka 集群。
(2)对配置文件修改后,希望能够快速同步到各个节点上。
2) 配置管理可交由ZooKeeper实现。
(1)可将配置信息写入ZooKeeper上的一个Znode。
(2)各个客户端服务器监听这个Znode。
(3)一旦Znode中的数据被修改,ZooKeeper将通知各个客户端服务器。

1)分布式环境中,实时掌握每个节点的状态是必要的。
(1)可根据节点实时状态做出一些调整。
2)ZooKeeper可以实现实时监控节点状态变化
(1)可将节点运行状态信息写入ZooKeeper上的一个ZNode。
(2)监听这个ZNode可获取它的实时状态变化。
相当于讲客户端所有的相关信息注册上之后,进行统一的集群管理,以及集群状态的好坏

服务器动态上下线

软负载均衡
在Zookeeper中记录每台服务器的访问数,让访问数最少的服务器去处理最新的客户端请求

服务器注册域名,下面有多台服务器,多台服务器有一个接客线程数,zookeeper根据每一个节点上对应的访问数来进行软负载均衡

1.5 下载地址
1)官网首页:
https://zookeeper.apache.org/
2)下载截图

选择相对稳定的老版本

第2章 Zookeeper本地安装
2.1 本地模式安装部署
1)安装前准备
(1)安装Jdk
(2)拷贝Zookeeper安装包到Linux系统下
先启动三台集群

(3)解压到指定目录

[leokadia@hadoop102 software]$ tar -zxvf apache-zookeeper-3.5.7-bin.tar.gz -C /opt/module/


查看

改名

[leokadia@hadoop102 module]$ mv apache-zookeeper-3.5.7-bin/ zookeeper-3.5.7  


2)配置修改
(1)将/opt/module/zookeeper-3.5.7/conf这个路径下的zoo_sample.cfg修改为zoo.cfg;

[leokadia@hadoop102 conf]$ mv zoo_sample.cfg zoo.cfg

(2)打开zoo.cfg文件,修改dataDir路径:

[leokadia@hadoop102 conf]$ vim zoo.cfg

/tmp存储的是临时数据,到了一个月会被删除掉,也就是到了1个月zookeeper数据都没了,于是需要创建一个目录进行保存,通常创建zkData

想把数据放在自己的框架下,于是在自己的目录下创建目录zkData

(3)在/opt/module/zookeeper-3.5.7/这个目录上创建zkData文件夹

[leokadia@hadoop102 zookeeper-3.5.7]$ mkdir zkData


在配置文件中修改如下内容:

dataDir=/opt/module/zookeeper-3.5.7/zkData

3)操作Zookeeper
(1)启动Zookeeper

[leokadia@hadoop102 zookeeper-3.5.7]$ bin/zkServer.sh start

(2)查看进程是否启动

[leokadia@hadoop102 zookeeper-3.5.7]$ jps

(3)查看状态:

[leokadia@hadoop102 zookeeper-3.5.7]$ bin/zkServer.sh status!


(4)启动客户端:

[leokadia@hadoop102 zookeeper-3.5.7]$ bin/zkCli.sh

(5)退出客户端:

[zk: localhost:2181(CONNECTED) 0] quit

(6)停止Zookeeper

[leokadia@hadoop102 zookeeper-3.5.7]$ bin/zkServer.sh stop

2.2 配置参数解读

Zookeeper中的配置文件zoo.cfg中参数含义解读如下:
1)tickTime =2000:通信心跳数,Zookeeper服务器与客户端心跳时间,单位毫秒
Zookeeper使用的基本时间,服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个tickTime时间就会发送一个心跳,时间单位为毫秒。
它用于心跳机制,并且设置最小的session超时时间为两倍心跳时间。(session的最小超时时间是2*tickTime)

即客户端与服务端,服务端与服务段2s中发一次通信

2)initLimit =10:LF初始通信时限
集群中的Follower跟随者服务器与Leader领导者服务器之间初始连接时能容忍的最多心跳数(tickTime的数量),用它来限定集群中的Zookeeper服务器连接到Leader的时限。

初始化在10个心跳(20s)还没有建立连接,这个通信就是失败的

3)syncLimit =5:LF同步通信时限
集群中Leader与Follower之间的最大响应时间单位,假如响应超过syncLimit * tickTime,Leader认为Follwer死掉,从服务器列表中删除Follwer。

4)dataDir:数据文件目录+数据持久化路径
主要用于保存Zookeeper中的数据。

注意:默认的tmp目录,容易被Linux系统定期删除,所以一般不用默认的tmp目录。

5)clientPort =2181:客户端连接端口
监听客户端连接的端口。通常情况下不做修改。

第3章 Zookeeper实战(开发重点)

3.1 分布式安装部署

1)集群规划
在hadoop102、hadoop103和hadoop104三个节点上部署Zookeeper。
2)解压安装
(1)解压Zookeeper安装包到/opt/module/目录下

[leokadia@hadoop102 software]$ tar -zxvf apache-zookeeper-3.5.7-bin.tar.gz -C /opt/module/

之前本地做过了

(2)同步/opt/module/zookeeper-3.5.7目录内容到hadoop103、hadoop104

[leokadia@hadoop102 module]$ xsync zookeeper-3.5.7/

3)配置服务器编号
(1)在/opt/module/zookeeper-3.5.7/这个目录下创建zkData

[leokadia@hadoop102 zookeeper-3.5.7]$ mkdir -p zkData

(2)在/opt/module/zookeeper-3.5.7/zkData目录下创建一个myid的文件

[leokadia@hadoop102 zkData]$ touch myid

添加myid文件,注意一定要在linux里面创建,在notepad++里面很可能乱码
(3)编辑myid文件

[leokadia@hadoop102 zkData]$ vi myid

在文件中添加与server对应的编号:
2

Hadoop102 配置2,hadoop103配置3,hadoop104配置4

(4)拷贝配置好的zookeeper到其他机器上

[leokadia@hadoop102 zkData]$ xsync myid

如果前面没分发,同步/opt/module/zookeeper-3.5.7目录内容到hadoop103、hadoop104,当然也可以等到后面一起分发

[leokadia@hadoop102 module]$ xsync zookeeper-3.5.7/

并分别在hadoop103、hadoop104上修改myid文件中内容为3、4



4)配置zoo.cfg文件
(1)重命名/opt/module/zookeeper-3.5.7/conf这个目录下的zoo_sample.cfg为zoo.cfg

[leokadia@hadoop102 conf]$ mv zoo_sample.cfg zoo.cfg

(2)打开zoo.cfg文件

[leokadia@hadoop102 conf]$ vim zoo.cfg

修改数据存储路径配置(在上文已经做过了)
dataDir=/opt/module/zookeeper-3.5.7/zkData
增加如下配置

#######################cluster##########################
server.2=hadoop102:2888:3888
server.3=hadoop103:2888:3888
server.4=hadoop104:2888:3888

(3)同步zoo.cfg配置文件

[leokadia@hadoop102 conf]$ xsync zoo.cfg


检查是否分发成功

hadoop103修改成功

(4)配置参数解读
server.A=B:C:D。
A是一个数字,表示这个是第几号服务器;
集群模式下配置一个文件myid,这个文件在dataDir目录下,这个文件里面有一个数据就是A的值,Zookeeper启动时读取此文件,拿到里面的数据与zoo.cfg里面的配置信息比较从而判断到底是哪个server。
B是这个服务器的地址;
C是这个服务器Follower与集群中的Leader服务器交换信息的端口;
D是万一集群中的Leader服务器挂了,需要一个端口来重新进行选举,选出一个新的Leader,而这个端口就是用来执行选举时服务器相互通信的端口。
5)集群操作
(1)分别启动Zookeeper

[leokadia@hadoop102 zookeeper-3.5.7]$ bin/zkServer.sh start
[leokadia@hadoop103 zookeeper-3.5.7]$ bin/zkServer.sh start
[leokadia@hadoop104 zookeeper-3.5.7]$ bin/zkServer.sh start

注:如果只启动一台集群查看状态,发现没有启动起来,因为此时是3台服务器,目前只启动一台服务器,没有达到超过半数,就不会选出对应的Leader,对应的集群就没法工作,集群必须要有超过半数以上的服务器是好的,才能正常工作

如何知道是否超过半数了呢?根据配置文件刚刚配置文件中写了有3台服务器


此时我们启动第二台服务器,可以发现hadoop103成为了leader

再查看hadoop102,发现其成为了follower

此时再启动hadoop104,查看状态

发现104为follower

(2)查看状态(见上图)

[leokadia@hadoop102 zookeeper-3.5.7]# bin/zkServer.sh status
JMX enabled by default
Using config: /opt/module/zookeeper-3.5.7/bin/../conf/zoo.cfg
Mode: follower
[leokadia@hadoop103 zookeeper-3.5.7]# bin/zkServer.sh status
JMX enabled by default
Using config: /opt/module/zookeeper-3.5.7/bin/../conf/zoo.cfg
Mode: leader
[leokadia@hadoop104 zookeeper-3.4.5]# bin/zkServer.sh status
JMX enabled by default
Using config: /opt/module/zookeeper-3.5.7/bin/../conf/zoo.cfg
Mode: follower

3.1.2 集群启动停止脚本

由于如果集群较多的话,每一台集群启动和停止都需要输入命令太过于繁琐,故编写脚本统一启动和停止。
1)在 hadoop102 的/home/leokadia/bin 目录下创建脚本

[leokadia@hadoop102 bin]$ vim zk.sh 

在脚本中编写如下内容

#!/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

2)增加脚本执行权限

[leokadia@hadoop102 bin]$ chmod 777 zk.sh 

3)Zookeeper 集群启动脚本
先启动一下hadoop集群

[leokadia@hadoop102 bin]$ jpsall

启动zk集群

[leokadia@hadoop102 bin]$ zk.sh start 


查看各集群状态:

[leokadia@hadoop102 bin]$ zk.sh status

4)Zookeeper 集群停止脚本

[leokadia@hadoop102 bin]$ zk.sh stop

3.2 客户端命令行操作

命令基本语法 功能描述
help 显示所有操作命令
ls path 使用 ls 命令来查看当前znode的子节点
-w 监听子节点变化
-s 附加次级信息
create 普通创建
-s 含有序列
-e 临时(重启或者超时消失)
get path 获得节点的值
-w 监听节点内容变化
-s 附加次级信息
set 设置节点的具体值
stat 查看节点状态
delete 删除节点
deleteall 递归删除节点

先启动集群

1)启动客户端

[leokadia@hadoop103 zookeeper-3.5.7]$ bin/zkCli.sh



启动之后发现是个本地的客户端,想要把它变成hadoop102或者103这种的客户端,先输入quit退出,再输入

[leokadia@hadoop102 zookeeper-3.5.7]$ bin/zkCli.sh -server hadoop102:2181

2)显示所有操作命令

[zk: localhost:2181(CONNECTED) 1] help

3)查看当前znode中所包含的内容

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

4)查看当前节点详细数据

[zk: localhost:2181(CONNECTED) 1] ls2 /
[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


(1)czxid:创建节点的事务 zxid
每次修改 ZooKeeper 状态都会产生一个 ZooKeeper 事务 ID。事务 ID 是 ZooKeeper 中所 有修改总的次序。每次修改都有唯一的 zxid,如果 zxid1 小于 zxid2,那么 zxid1 在 zxid2 之 前发生。
(2)ctime:znode 被创建的毫秒数(从 1970 年开始)
(3)mzxid:znode 最后更新的事务 zxid
(4)mtime:znode 最后修改的毫秒数(从 1970 年开始)
(5)pZxid:znode 最后更新的子节点 zxid (存储的是树形结构)
(6)cversion:znode 子节点变化号,znode 子节点修改次数
(7)dataversion:znode 数据变化号
(8)aclVersion:znode 访问控制列表的变化号
(9)ephemeralOwner:如果是临时节点,这个是 znode 拥有者的 session id。如果不是 临时节点则是 0。
(10)dataLength:znode 的数据长度
(11)numChildren:znode 子节点数量

1)分别创建2个普通节点(永久节点)还是用的漫威的例子

[zk: hadoop102:2181(CONNECTED) 7] create /hero "ironman"
Created /hero
[zk: hadoop102:2181(CONNECTED) 9] create /hero/Marvel "Hulk"
Created /hero/Marvel

2)获得节点的值

[zk: hadoop102:2181(CONNECTED) 12] get -s /hero
ironman
cZxid = 0x300000006
ctime = Sat Nov 27 08:07:39 CST 2021
mZxid = 0x300000006
mtime = Sat Nov 27 08:07:39 CST 2021
pZxid = 0x300000007
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 7
numChildren = 1
[zk: hadoop102:2181(CONNECTED) 13] get -s /hero/Marvel
Hulk
cZxid = 0x300000007
ctime = Sat Nov 27 08:10:48 CST 2021
mZxid = 0x300000007
mtime = Sat Nov 27 08:10:48 CST 2021
pZxid = 0x300000007
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 4
numChildren = 0


3)创建带序号的节点(永久节点 + 带序号)

[zk: hadoop102:2181(CONNECTED) 4] create -s /hero/DC/Batman "Batman"
Created /hero/DC/Batman0000000000

那么带序号和不带序号的节点有什么区别吗?
带序号的节点可以创建相同名称的节点,序号自动加1,不带序号的不能重复创建同名结点。

验证退出客户端,节点是否还是存在

节点没有被删除


如果原来没有序号节点,序号从 0 开始依次递增。如果原节点下已有 2 个节点,则再排 序时从 2 开始,以此类推。

[zk: hadoop102:2181(CONNECTED) 14] create -e /hero/Darkhorse "darkhorse"
Created /hero/Darkhorse
[zk: hadoop102:2181(CONNECTED) 15] create -e -s /hero/Darkhorse "darkhorse"
Created /hero/Darkhorse0000000003


退出后,发现临时节点消失

9)修改节点数据值

[zk: hadoop102:2181(CONNECTED) 3] set -s /hero/DC "DC"

3.2.4 监听器原理

客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、节点删除、子目 录节点增加删除)时,ZooKeeper 会通知客户端。监听机制保证 ZooKeeper 保存的任何的数 据的任何改变都能快速的响应到监听了该节点的应用程序。

1、监听原理详解

  • 1)首先在要有一个main()线程
  • 2)在main线程中创建Zookeeper客户端,这时就会创建两个线程,一个负责网络连接通信(connet),一个负责监听(listener)。
  • 3)通过connect线程将注册的监听事件发送给Zookeeper。
  • 4)在Zookeeper的注册监听器列表中将注册的监听事件添加到列表中。
  • 5)Zookeeper监听到有数据或路径变化,就会将这个消息发送给listener线程。
  • 6)listener线程内部调用了process()方法。


2、常见的监听
1)监听节点数据的变化
get path [watch]
2)监听子节点增减的变化
ls path [watch]


10)节点的值变化监听
(1)在hadoop104主机上注册监听/hero节点数据变化

[zk: localhost:2181(CONNECTED) 1] get -w /hero

(2)在hadoop103主机上修改/sanguo节点的数据

[zk: localhost:2181(CONNECTED) 0] set /hero "Avengers"

(3)观察hadoop104主机收到数据变化的监听

WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/hero


再次修改数据,hadoop104无变化,监听不到


注意:在hadoop103再多次修改/hero的值,hadoop104上不会再收到监听。因为注册 一次,只能监听一次。想再次监听,需要再次注册。

2)节点的子节点变化监听(路径变化)
(1)在hadoop104主机上注册监听/sanguo节点的子节点变化

[zk: localhost:2181(CONNECTED) 1] ls -w/hero

(2)在hadoop103主机/sanguo节点上创建子节点

[zk: localhost:2181(CONNECTED) 0] create /hero/Disney "Woody"
Created /hero/Disney

(3)观察hadoop104主机收到子节点变化的监听

WATCHER::
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/hero


同理,再在hadoop103创建子节点,hadoop104上不会再收到监听。因为注册一次,只能监听一次。想再次监听,需要再次注册。

注意:节点的路径变化,也是注册一次,生效一次。想多次生效,就需要多次注册。

3.2.5 节点删除与查找

12)删除节点

[zk: localhost:2181(CONNECTED) 7] delete /hero/Disney

2)递归删除节点

[zk: localhost:2181(CONNECTED) 15] deleteall/hero

3)查看节点状态

[zk: localhost:2181(CONNECTED) 17] stat /zookeeper

3.3 客户端API应用

3.3.1 IDEA环境搭建

1)创建一个Maven工程

2)添加pom文件

<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>RELEASE</version>
		</dependency>
		
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-core</artifactId>
			<version>2.8.2</version>
		</dependency>
		
		<dependency>
			<groupId>org.apache.zookeeper</groupId>
			<artifactId>zookeeper</artifactId>
			<version>3.5.7</version>
		</dependency>
</dependencies>


3)拷贝log4j.properties文件到项目根目录
需要在项目的src/main/resources目录下,新建一个文件,命名为“log4j.properties”,在文件中填入。

log4j.rootLogger=INFO, stdout  
log4j.appender.stdout=org.apache.log4j.ConsoleAppender  
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout  
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n  
log4j.appender.logfile=org.apache.log4j.FileAppender  
log4j.appender.logfile.File=target/spring.log  
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout  
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n  


3.3.2 创建ZooKeeper客户端

public class zkClient 

    // 注意:逗号左右不能有空格
    private String connectString = "hadoop102:2181,hadoop103:2181,hadoop104:2181";
    private int sessionTimeout = 2000;
    private ZooKeeper zkClient;

    @Before
    public void init() throws IOException 

        zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() 
            @Override
            public void process(WatchedEvent watchedEvent) 

            
        );
    



3.3.3 创建子节点

    @Test
    public void create() throws KeeperException, InterruptedException 
        String nodeCreated = zkClient.create("/leokadia", "sa.avi".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);//创建持久节点
    


在hadoop103上验证是否创建对应节点,创建成功

3.3.4 获取子节点并监听节点变化

@Test
public void getChildren(以上是关于超全zookeeper知识点与实战的主要内容,如果未能解决你的问题,请参考以下文章

Paxos算法与Zookeeper分析

Paxos算法与Zookeeper分析

超全108套项目实战大集合

Maven实战与原理分析:maven超全使用指南总结

Maven实战与原理分析:maven超全使用指南总结

zookeeper原理及搭建