Zookeeper学习笔记

                <svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
                    <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
                </svg>
                <p></p>


前言

关于源码部分,静等工作之后再学习。本文是参考尚硅谷大海哥的讲义来进行学习笔记的编辑的。


一、Zookeeper入门

1.1 概述

Zookeeper 是一个开源的分布式的,为分布式框架提供协调服务的Apache 项目。
在这里插入图片描述
在这里插入图片描述

1.2 特点

在这里插入图片描述

1.3 数据结构

在这里插入图片描述

1.4 应用场景

提供的服务包括:统一命名服务、统一配置服务、统一集群管理、服务器节点动态上下线、软负载均衡等。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.5 下载

1.官网

2.下载截图
在这里插入图片描述
3.如果要下载旧版本,操作如下图。
在这里插入图片描述
4.选择3.5.7
在这里插入图片描述
5.下载 Linux环境安装的 tar包
在这里插入图片描述

二、Zookeeper本地安装

2.1 安装及配置

  1. mkdir /opt/softwaremkdir /opt/module前面一个是解压目录,后面一个是安装目录
  2. 检查系统中是否有jdk======java -version
  3. 将压缩包拷贝到 /opt/software 目录下
  4. 解压到指定目录 tar -zxvf apache-zookeeper-3.5.7-bin-tar-ge -C /opt/module
  5. 通常我们需要修改名称,修改为 mv apache-zookeeper-3.5.7 -bin/zookeeper-3.5.7
  6. /opt/module/zookeeper-3.5.7/conf 这个路径下的 zoo_sample.cfg修改为 zoo.cfg
    操作: mv zoo_sample.cfg zoo.cfg
  7. 打开zoo.cfg文件,修改dataDir路径,因为数据默认是存放到临时路径下的,临时路径/tmp这个会被定时清理,所以我们需要自己在 /opt/module/zookeeper-3.5.7/ 这个目录上创建zkData文件夹。然后在zoo.cfg文件中修改如下内容:

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

2.2 启动与关闭客户端

  1. 启动客户端 bin/zkServer.sh start
    在这里插入图片描述
  2. 查看进程是否启动
    在这里插入图片描述
  3. 查看状态 bin/zkServer.sh status
    在这里插入图片描述
  4. 启动客户端 bin/zkCli.sh

在这里插入图片描述

  1. 退出客户端 quit

在这里插入图片描述

  1. 停止Zookeeper bin/zkServer.sh stop
    在这里插入图片描述

2.2 配置参数详解

Zookeeper中的配置文件zoo.cfg中参数含义解读如下:

  • 1)tickTime = 2000:通信心跳时间,Zookeeper服务器与客户端心跳时间,单位毫秒。
    在这里插入图片描述
  • 2)initLimit = 10:LF初始通信时限
    在这里插入图片描述
  • 3)syncLimit = 5:LF同步通信时限
    在这里插入图片描述
  • 4)dataDir:保存Zookeeper中的数据
    注意:默认的tmp目录,容易被Linux系统定期删除,所以一般不用默认的tmp目录。
  • 5)clientPort = 2181:客户端连接端口,通常不做修改。

三、Zookeeper集群操作

3.1 集群操作

1)集群规划
在hadoop102、 hadoop103和 hadoop104三个 节点上 都部署 Zookeeper。
思考:如果是10台服务器,需要部署多少台 Zookeeper?


2)解压安装
(1) 在 hadoop102解压 Zookeeper安装包到 /opt/module/目录下
在这里插入图片描述
(2)修改 apache-zookeeper-3.5.7-bin名称为 zookeeper-3.5.7
在这里插入图片描述


3)配置服务器编号
(1)在 /opt/module/zookeeper-3.5.7/这个目录下创建 zkData
在这里插入图片描述
(2)在 /opt/module/zookeeper-3.5.7/zkData目录下创建一个 myid的文件
在这里插入图片描述
在文件中添加与server对应的编号 (注意:上下不要有空行,左右不要有空格
注意添加 myid文件,一定要在 Linux里面创建,在 notepad++里面很可能乱码
(3)将前面的步骤在另外两个虚拟机中重复进行:

最终结果呈现:
编号3:192.168.249.103
编号4:192.168.249.104
编号5:192.168.249.105


4)配置zoo.cfg文件
(1)重命名 /opt/module/zookeeper-3.5.7/conf这个目录下的 zoo_sample.cfg为 zoo.cfg
在这里插入图片描述
在这里插入图片描述

  • 增加如下配置

##########cluster#############
server.2=192.168.249.103:2888:3888
server.3=192.168.249.104:2888:3888
server.4=192.168.249.105:2888:3888

配置参数解读:
在这里插入图片描述
(4)在另外两台虚拟机中进行同样的配置
注意:笔记中的handoop是老师课件中的,这是本机的hostname,实际中我这里显示的是虚拟机的IP地址。


5)集群操作
在这里插入图片描述
在这里插入图片描述


3.2 选举机制(面试重点)

在这里插入图片描述
在这里插入图片描述

3.3 ZK集群启动停止脚本

在上一步中我们创建了zookeeper集群,但是每次启动是不是都要进入zookeeper安装目录中去进行执行启动,停止,查看状态脚本呢。如果有100台呢,所以我们可以去设置一个批量启动脚本来进行集群批量启动等状态。

  1. 在根目录下的bin目录中创建一个脚本文件,zk.sh
    在这里插入图片描述
  2. 编辑 vim zk.sh

具体参考脚本代码如下:

#!/bin/bash

case $1 in
"start"){
for i in 192.168.249.103 192.168.249.104 192.168.249.105
do
echo ------------- zookeeper $i 启动 ------------
sshpass -p "atguigu@" ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh start"
done
}
;;
"stop"){

    <span class="token keyword">for</span> <span class="token for-or-select variable">i</span> <span class="token keyword">in</span> <span class="token number">192.168</span>.249.103 <span class="token number">192.168</span>.249.104 <span class="token number">192.168</span>.249.105
    <span class="token keyword">do</span>
            <span class="token builtin class-name">echo</span> -------------  zookeeper <span class="token variable">$i</span> 停止 ------------
            sshpass -p <span class="token string">"atguigu@"</span>   <span class="token function">ssh</span> <span class="token variable">$i</span> <span class="token string">"/opt/module/zookeeper-3.5.7/bin/zkServer.sh stop"</span>

    <span class="token keyword">done</span>

}
;;
"status"){
for i in 192.168.249.103 192.168.249.104 192.168.249.105
do
echo ------------- zookeeper $i 状态 ------------
sshpass -p "atguigu@" ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh status"
done
}
;;
esac


当然也可以参考网上其他人的:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


  1. 编辑脚本完成之后,具体启动、停止、查看状态命令如下:

编辑完后,进行脚本执行权限 chmod 777 zk.sh
启动脚本:zk.sh start
停止脚本:zk.sh stop

3.4 客户端操作

3.4.1 命令行操作

在这里插入图片描述

3.4.2 znode节点数据信息

在这里插入图片描述
(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 子节点数量

3.4.3 节点类型(持久/短暂/有序/无序)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.4.4 监听器原理

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

3.4.5 节点删除与查看

在这里插入图片描述

3.5 客户端API操作

前提:保证 hadoop102、 hadoop103、 hadoop104服务器上 Zookeeper集群服务端启动。

3.5.1 IDEA环境搭建

1)创建一个工程:zookeeper
2)添加pom文件

<dependencies>
     <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>RELEASE</version>
        </dependency>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.apache.logging.log4j<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>log4j-core<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>2.8.2<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.apache.zookeeper<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>zookeeper<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>3.5.7<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>

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

4)创建包名com.atguigu.zk
5)创建类名称zkClient

3.5.2 创建 ZooKeeper客户端

在这里插入图片描述
在这里插入图片描述

3.5.3 创建子节点

在这里插入图片描述

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

在这里插入图片描述

3.5.5 判断 Znode是否存在

在这里插入图片描述
在这里插入图片描述


下面是我自己参考老师上课所讲的内容写的代码,仅供参考:
@Before – 表示在任意使用@Test注解标注的public void方法执行之前执行

package com.atguigu.zk;

public class zkClient {

<span class="token keyword">private</span> <span class="token class-name">String</span> connectString <span class="token operator">=</span> <span class="token string">"192.168.249.103:2181,192.168.249.104:2181,192.168.249.105:2181"</span><span class="token punctuation">;</span>

<span class="token keyword">private</span> <span class="token keyword">int</span> sessionTimeout <span class="token operator">=</span> <span class="token number">2000000</span><span class="token punctuation">;</span>

<span class="token keyword">private</span> <span class="token class-name">ZooKeeper</span> zkClient<span class="token punctuation">;</span>

<span class="token comment">//    @Test</span>
<span class="token annotation punctuation">@Before</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">{<!-- --></span>
    zkClient <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ZooKeeper</span><span class="token punctuation">(</span>connectString<span class="token punctuation">,</span> sessionTimeout<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Watcher</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token annotation punctuation">@Override</span>
        <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">process</span><span class="token punctuation">(</span><span class="token class-name">WatchedEvent</span> watchedEvent<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>


            <span class="token comment">//如果没有下面代码,那么就只监听一次, 如有,则实时监听</span>

              <span class="token comment">//监听代码</span>

// System.out.println("----------------------------------");
// //监听实时变化
// //监听根目录下
// List<String> children = null;
// try {
// children = zkClient.getChildren("/", true);
//
// for (String child: children) {
// System.out.println(child);
// }
// System.out.println("----------------------------------");
//
// } catch (KeeperException e) {
// e.printStackTrace();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }

        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>


<span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span><span class="token punctuation">,</span> <span class="token class-name">KeeperException</span> <span class="token punctuation">{<!-- --></span>


    <span class="token comment">//参数1:要创建的节点的路径;</span>
    <span class="token comment">//参数2:节点数据</span>
    <span class="token comment">//参数3:节点权限</span>
    <span class="token comment">//参数4:节点的类型</span>
    <span class="token class-name">String</span> nodeCreated <span class="token operator">=</span> zkClient<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string">"/atguigu"</span><span class="token punctuation">,</span> <span class="token string">"ss.avi"</span><span class="token punctuation">.</span><span class="token function">getBytes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">ZooDefs<span class="token punctuation">.</span>Ids</span><span class="token punctuation">.</span>OPEN_ACL_UNSAFE<span class="token punctuation">,</span> <span class="token class-name">CreateMode</span><span class="token punctuation">.</span>PERSISTENT<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>


<span class="token comment">//监听实时变化</span>
<span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">getChildren</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span><span class="token punctuation">,</span> <span class="token class-name">KeeperException</span> <span class="token punctuation">{<!-- --></span>
    <span class="token comment">//true  开启监听</span>
    <span class="token comment">//此处为true,监听使用的是init()方法中的new Watcher()监听</span>
    <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> children <span class="token operator">=</span> zkClient<span class="token punctuation">.</span><span class="token function">getChildren</span><span class="token punctuation">(</span><span class="token string">"/"</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">String</span> child <span class="token operator">:</span> children<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>child<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">//设置延时(否则马上就执行完,再创建一个,控制台监听不到)</span>
    <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token class-name">Long</span><span class="token punctuation">.</span>MAX_VALUE<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>


<span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">exist</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span><span class="token punctuation">,</span> <span class="token class-name">KeeperException</span> <span class="token punctuation">{<!-- --></span>
    <span class="token class-name">Stat</span> stat <span class="token operator">=</span> zkClient<span class="token punctuation">.</span><span class="token function">exists</span><span class="token punctuation">(</span><span class="token string">"/atguigu"</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>stat <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">?</span> <span class="token string">"not exist"</span> <span class="token operator">:</span> <span class="token string">"exist"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token punctuation">}</span>

}

启动客户端报错:org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss for /atguigu(这个bug我弄了2个小时,实在无可奈何,哎!只能放上大招了)

网上查找解决办法 :
经过调试发现 private static final int sessionTimeout = 1000 中设置的sessionTimeout值太小,应增大此值,问题解决。
解释:sessionTimeout是会话超时时间,也就是当一个zookeeper超过该时间没有心跳,则认为该节点故障。所以,如果此值小于zookeeper的创建时间,则当zookeeper还未来得及创建连接,会话时间已到,因此抛出异常认为该节点故障。
在这里插入图片描述

3.6 客户端向服务端写数据流程

在这里插入图片描述

四、服务器动态上下线监听案例

4.1 需求

某分布式系统中,主节点可以有多台,可以动态上下线,任意一台客户端都能实时感知到主节点服务器的上下线。

4.2 需求分析

在这里插入图片描述

4.3 代码实现

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


自己编写的服务器端代码实现如下:

package com.atguigu.case1;

/**服务器

  • @author wystart

  • @create 2022-08-17 12:41
    */
    public class DistributeServer {

    private String connectString = "192.168.249.103:2181,192.168.249.104:2181,192.168.249.105:2181";
    private int sessionTimeout = 2000000;
    private ZooKeeper zooKeeper;

    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {

     <span class="token class-name">DistributeServer</span> server <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DistributeServer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token comment">//1.获取zk连接,将服务器和zk集群相连接</span>
     server<span class="token punctuation">.</span><span class="token function">getConnect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    
     <span class="token comment">//2.注册服务器到zk集群,注册其实就是创建/servers下路径,即创建节点</span>
     server<span class="token punctuation">.</span><span class="token function">regist</span><span class="token punctuation">(</span>args<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//在启动的时候通过args传入主机名称</span>
    
    
     <span class="token comment">//3.启动业务逻辑(让进程不要一下子就执行完了,让其睡觉)</span>
     server<span class="token punctuation">.</span><span class="token function">business</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    

    }

    private void business() throws InterruptedException {
    Thread.sleep(Long.MAX_VALUE);

    }

    //将主机名称传入,进行注册(启动一台,注册一台)
    private void regist(String hostname) throws InterruptedException, KeeperException {

     <span class="token comment">//创建临时带序号的节点</span>
     <span class="token class-name">String</span> create <span class="token operator">=</span> zooKeeper<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string">"/servers/"</span> <span class="token operator">+</span> hostname<span class="token punctuation">,</span> hostname<span class="token punctuation">.</span><span class="token function">getBytes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">ZooDefs<span class="token punctuation">.</span>Ids</span><span class="token punctuation">.</span>OPEN_ACL_UNSAFE<span class="token punctuation">,</span> <span class="token class-name">CreateMode</span><span class="token punctuation">.</span>EPHEMERAL_SEQUENTIAL<span class="token punctuation">)</span><span class="token punctuation">;</span>
    
    
     <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>hostname <span class="token operator">+</span> <span class="token string">"  is online"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    

    }

    //创建到 zk 的客户端连接
    public void getConnect() throws IOException {

     zooKeeper <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ZooKeeper</span><span class="token punctuation">(</span>connectString<span class="token punctuation">,</span> sessionTimeout<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Watcher</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
         <span class="token annotation punctuation">@Override</span>
         <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">process</span><span class="token punctuation">(</span><span class="token class-name">WatchedEvent</span> watchedEvent<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    
         <span class="token punctuation">}</span>
     <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    

    }

}

客户端代码实现

package com.atguigu.case1;
/**
 * 客户端
 *
 * @author wystart
 * @create 2022-08-17 13:10
 */
public class DistributeClient {
<span class="token keyword">private</span> <span class="token class-name">ZooKeeper</span> zooKeeper<span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> connectString <span class="token operator">=</span> <span class="token string">"192.168.249.103:2181,192.168.249.104:2181,192.168.249.105:2181"</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token keyword">int</span> sessionTimeout <span class="token operator">=</span> <span class="token number">2000000</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span><span class="token punctuation">,</span> <span class="token class-name">InterruptedException</span><span class="token punctuation">,</span> <span class="token class-name">KeeperException</span> <span class="token punctuation">{<!-- --></span>
    <span class="token class-name">DistributeClient</span> client <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DistributeClient</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>


    <span class="token comment">//1.获取zk连接</span>
    client<span class="token punctuation">.</span><span class="token function">getConnect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">//2.监听/servers下面子节点的增加和删除</span>
    client<span class="token punctuation">.</span><span class="token function">getServerList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">//3.业务逻辑(睡觉)</span>
    client<span class="token punctuation">.</span><span class="token function">business</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>


<span class="token punctuation">}</span>

<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">business</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">{<!-- --></span>

    <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token class-name">Long</span><span class="token punctuation">.</span>MAX_VALUE<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">//获取服务器列表信息</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">getServerList</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">InterruptedException</span><span class="token punctuation">,</span> <span class="token class-name">KeeperException</span> <span class="token punctuation">{<!-- --></span>

    <span class="token comment">//监听/servers这个节点下数据的变化,如果参数写的是true,表示使用的是getConnect():初始化里面的监听器,否则需要我们自己创建</span>
    <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> children <span class="token operator">=</span> zooKeeper<span class="token punctuation">.</span><span class="token function">getChildren</span><span class="token punctuation">(</span><span class="token string">"/servers"</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>


    <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> servers <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">//遍历子节点,取出主机名称,判断是否上下线,然后封装到一个list集合中进行打印</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">String</span> child <span class="token operator">:</span> children<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>


        <span class="token comment">//获取子节点对应的值</span>
        <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> data <span class="token operator">=</span> zooKeeper<span class="token punctuation">.</span><span class="token function">getData</span><span class="token punctuation">(</span><span class="token string">"/servers/"</span> <span class="token operator">+</span> child<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">//加到集合中</span>
        servers<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">//打印</span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>servers<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token punctuation">}</span>

<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">getConnect</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">{<!-- --></span>

    zooKeeper <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ZooKeeper</span><span class="token punctuation">(</span>connectString<span class="token punctuation">,</span> sessionTimeout<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Watcher</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token annotation punctuation">@Override</span>
        <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">process</span><span class="token punctuation">(</span><span class="token class-name">WatchedEvent</span> watchedEvent<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>


            <span class="token comment">//如果这里没有加,则只会监听一次(因为只注册了一次),在初始化这里加了之后,实时监听</span>
            <span class="token keyword">try</span> <span class="token punctuation">{<!-- --></span>
                <span class="token function">getServerList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">KeeperException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>

        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>


<span class="token punctuation">}</span>

}

4.4 测试

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述在这里插入图片描述

五、Zookeeper分布式锁案例

5.1 需求

什么叫做分布式锁呢?

比如说 “进程 1” 在使用该资源的时候,会先去获得锁,"进程 1"获得锁以后会对该资源保持独占,这样其他进程就无法访问该资源,"进程1"用完该资源以后就将锁释放掉,让其他进程来获得锁,那么通过这个锁机制,我们就能保证了 分布式系统中多个进程能够有序的访问该临界资源。那么我们把这个分布式环境下的这个锁叫作分布式锁

5.2 需求分析

在这里插入图片描述

5.3 原生Zookeeper实现分布式锁案例

5.3.1 代码具体实现

DistributedLock

package com.atguigu.case2;
/**
 * @author wystart
 * @create 2022-08-17 23:19
 */
public class DistributedLock {
<span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">String</span> connectString <span class="token operator">=</span> <span class="token string">"192.168.249.103:2181,192.168.249.104:2181,192.168.249.105:2181"</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token keyword">int</span> sessionTimeOut <span class="token operator">=</span> <span class="token number">200000</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">ZooKeeper</span> zk<span class="token punctuation">;</span>

<span class="token keyword">private</span> <span class="token class-name">CountDownLatch</span> countLatch <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CountDownLatch</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//等待前一步骤完成,下一步骤才进行执行</span>
<span class="token keyword">private</span> <span class="token class-name">CountDownLatch</span> waitLatch <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CountDownLatch</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">private</span> <span class="token class-name">String</span> currentMode<span class="token punctuation">;</span>
<span class="token comment">//前一个节点的路径</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> waitPath<span class="token punctuation">;</span>


<span class="token keyword">public</span> <span class="token class-name">DistributedLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span><span class="token punctuation">,</span> <span class="token class-name">InterruptedException</span><span class="token punctuation">,</span> <span class="token class-name">KeeperException</span> <span class="token punctuation">{<!-- --></span>

    <span class="token comment">// 获取连接</span>
    zk <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ZooKeeper</span><span class="token punctuation">(</span>connectString<span class="token punctuation">,</span> sessionTimeOut<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Watcher</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token annotation punctuation">@Override</span>
        <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">process</span><span class="token punctuation">(</span><span class="token class-name">WatchedEvent</span> watchedEvent<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>

            <span class="token comment">//监听器中判断释放的时机</span>
            <span class="token comment">//connectLatch  如果连接上zk 可以释放</span>
            <span class="token comment">//判断监听的事件的状态是否是连接</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>watchedEvent<span class="token punctuation">.</span><span class="token function">getState</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token class-name">Event<span class="token punctuation">.</span>KeeperState<span class="token punctuation">.</span>SyncConnected</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                <span class="token comment">//如果是,释放掉</span>
                countLatch<span class="token punctuation">.</span><span class="token function">countDown</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>

            <span class="token comment">//waitLatch 需要释放</span>
            <span class="token comment">//如果节点的删除而且节点路径时前一个节点路径,证明前一个节点已经下线</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>watchedEvent<span class="token punctuation">.</span><span class="token function">getType</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">==</span> <span class="token class-name">Event<span class="token punctuation">.</span>EventType<span class="token punctuation">.</span>NodeDeleted</span> <span class="token operator">&amp;&amp;</span> watchedEvent<span class="token punctuation">.</span><span class="token function">getPath</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>waitPath<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>
                waitLatch<span class="token punctuation">.</span><span class="token function">countDown</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>


    <span class="token comment">//  等待zk正常连接后,才往下执行程序,使得代码健壮性更强</span>
    countLatch<span class="token punctuation">.</span><span class="token function">await</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// 判断根节点/locks是否存在</span>
    <span class="token class-name">Stat</span> stat <span class="token operator">=</span> zk<span class="token punctuation">.</span><span class="token function">exists</span><span class="token punctuation">(</span><span class="token string">"/locks"</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>stat <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token comment">// 创建一下根节点</span>
        zk<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string">"/locks"</span><span class="token punctuation">,</span> <span class="token string">"locks"</span><span class="token punctuation">.</span><span class="token function">getBytes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">ZooDefs<span class="token punctuation">.</span>Ids</span><span class="token punctuation">.</span>OPEN_ACL_UNSAFE<span class="token punctuation">,</span> <span class="token class-name">CreateMode</span><span class="token punctuation">.</span>PERSISTENT<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>


<span class="token punctuation">}</span>


<span class="token comment">// 对zk加锁    其实就是在/locks 目录下创建临时有序的节点</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">zkLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    <span class="token comment">//创建对应的临时有序号的节点</span>
    <span class="token keyword">try</span> <span class="token punctuation">{<!-- --></span>
        currentMode <span class="token operator">=</span> zk<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token string">"/locks/"</span> <span class="token operator">+</span> <span class="token string">"seq-"</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token class-name">ZooDefs<span class="token punctuation">.</span>Ids</span><span class="token punctuation">.</span>OPEN_ACL_UNSAFE<span class="token punctuation">,</span> <span class="token class-name">CreateMode</span><span class="token punctuation">.</span>EPHEMERAL_SEQUENTIAL<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">// wait 一小会,让结果更清晰一些</span>
        <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">//判断创建的节点是否是最小的序号节点,如果是获取到锁,如果不是,监听它序号前一个节点</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> children <span class="token operator">=</span> zk<span class="token punctuation">.</span><span class="token function">getChildren</span><span class="token punctuation">(</span><span class="token string">"/locks"</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>


        <span class="token comment">//如果children 只有一个值,那就直接获取锁,如果有多个节点,需要判断,谁最小</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>children<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>

            <span class="token comment">//直接返回,获取到锁</span>
            <span class="token keyword">return</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{<!-- --></span>

            <span class="token comment">//如果有多个节点,需要取出来进行比较</span>
            <span class="token comment">//对节点排序</span>
            <span class="token class-name">Collections</span><span class="token punctuation">.</span><span class="token function">sort</span><span class="token punctuation">(</span>children<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment">// 获取节点名称 seq-00000000</span>
            <span class="token class-name">String</span> thisNode <span class="token operator">=</span> currentMode<span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span><span class="token string">"/locks/"</span><span class="token punctuation">.</span><span class="token function">length</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment">// 通过seq-00000000获取该节点在children集合的位置</span>
            <span class="token keyword">int</span> index <span class="token operator">=</span> children<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span>thisNode<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment">//判断</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"数据异常"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                <span class="token comment">//就一个节点,可以获取锁了</span>
                <span class="token keyword">return</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{<!-- --></span>
                <span class="token comment">//如果不止一个节点,就需要进行监听了</span>
                <span class="token comment">//waitPath(前一个节点的路径):需要监听,它前一个节点的变化</span>
                waitPath <span class="token operator">=</span> <span class="token string">"/locks/"</span> <span class="token operator">+</span> children<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>index <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                zk<span class="token punctuation">.</span><span class="token function">getData</span><span class="token punctuation">(</span>waitPath<span class="token punctuation">,</span><span class="token boolean">true</span><span class="token punctuation">,</span><span class="token keyword">new</span> <span class="token class-name">Stat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token comment">// 等待监听</span>
                waitLatch<span class="token punctuation">.</span><span class="token function">await</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token keyword">return</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>



        <span class="token punctuation">}</span>


    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">KeeperException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>


<span class="token punctuation">}</span>


<span class="token comment">// 解锁  其实就是删除 /locks目录下的临时节点</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">unZkLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>

    <span class="token comment">//删除节点</span>
    <span class="token keyword">try</span> <span class="token punctuation">{<!-- --></span>
        zk<span class="token punctuation">.</span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>currentMode<span class="token punctuation">,</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">KeeperException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

<span class="token punctuation">}</span>

}

5.3.2 测试

package com.atguigu.case2;
/**
 * @author wystart
 * @create 2022-08-17 23:20
 */
public class DistributedLockTest {
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span><span class="token punctuation">,</span> <span class="token class-name">InterruptedException</span><span class="token punctuation">,</span> <span class="token class-name">KeeperException</span> <span class="token punctuation">{<!-- --></span>
    <span class="token keyword">final</span> <span class="token class-name">DistributedLock</span> lock1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DistributedLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">final</span> <span class="token class-name">DistributedLock</span> lock2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DistributedLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>


    <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Runnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token annotation punctuation">@Override</span>
        <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>

            <span class="token keyword">try</span> <span class="token punctuation">{<!-- --></span>
                lock1<span class="token punctuation">.</span><span class="token function">zkLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"线程1 启动 , 获取到锁"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                lock1<span class="token punctuation">.</span><span class="token function">unZkLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"线程1  释放锁"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">5</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>


        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>


    <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Runnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token annotation punctuation">@Override</span>
        <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>

            <span class="token keyword">try</span> <span class="token punctuation">{<!-- --></span>
                lock2<span class="token punctuation">.</span><span class="token function">zkLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"线程2 启动 , 获取到锁"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                lock2<span class="token punctuation">.</span><span class="token function">unZkLock</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"线程2  释放锁"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">5</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">InterruptedException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>


        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>


<span class="token punctuation">}</span>

}

在这里插入图片描述
在这里插入图片描述

5.4 Curator框架实现分布式锁案例

1 )原生的 Java API开发存在的问题
(1) 会话连接是异步的,需要自己去处理。比如使用 CountDownLatch
(2) Watch需要重复注册,不然就不能生效
(3)开发的复杂性还是比较高的
(4)不支持多节点删除和创建。需要自己去递归
2) Curator是一个专门解决分布式锁的框架,解决了原生 Java API开发分布式遇到的问题。
详情请查看官方文档: 官方文档点这

5.4.1 具体代码实现

添加依赖:

<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.3.0</version>
        </dependency>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.apache.curator<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>curator-recipes<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>4.3.0<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>

    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.apache.curator<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>curator-client<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>4.3.0<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>

代码如下:

package com.atguigu.case3;
/**
 * @author wystart
 * @create 2022-08-18 12:41
 */
public class CuratorLockTest {
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>


    <span class="token comment">//创建分布式锁1</span>
    <span class="token class-name">InterProcessMutex</span> lock1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">InterProcessMutex</span><span class="token punctuation">(</span><span class="token function">getCuratorFrameWork</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">"/locks"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//创建分布式锁2</span>
    <span class="token class-name">InterProcessMutex</span> lock2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">InterProcessMutex</span><span class="token punctuation">(</span><span class="token function">getCuratorFrameWork</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">"/locks"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Runnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token annotation punctuation">@Override</span>
        <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
            <span class="token comment">//获取锁对象</span>
            <span class="token keyword">try</span> <span class="token punctuation">{<!-- --></span>
                lock1<span class="token punctuation">.</span><span class="token function">acquire</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"线程1 获取到锁"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token comment">//测试锁重入</span>
                lock1<span class="token punctuation">.</span><span class="token function">acquire</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"线程1 再次获取到锁"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">5</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                lock1<span class="token punctuation">.</span><span class="token function">release</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"线程1 释放锁"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                lock1<span class="token punctuation">.</span><span class="token function">release</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"线程1 再次释放锁"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>



    <span class="token keyword">new</span> <span class="token class-name">Thread</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Runnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token annotation punctuation">@Override</span>
        <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
            <span class="token comment">//获取锁对象</span>
            <span class="token keyword">try</span> <span class="token punctuation">{<!-- --></span>
                lock2<span class="token punctuation">.</span><span class="token function">acquire</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"线程2 获取到锁"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token comment">//测试锁重入</span>
                lock2<span class="token punctuation">.</span><span class="token function">acquire</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"线程2 再次获取到锁"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">5</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                lock2<span class="token punctuation">.</span><span class="token function">release</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"线程2 释放锁"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

                lock2<span class="token punctuation">.</span><span class="token function">release</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"线程2 再次释放锁"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
                e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>



<span class="token punctuation">}</span>

<span class="token comment">//分布式锁初始化</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">CuratorFramework</span> <span class="token function">getCuratorFrameWork</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    <span class="token comment">//重试策略</span>
    <span class="token comment">//失败之后重试的时间和次数</span>
    <span class="token class-name">ExponentialBackoffRetry</span> retry <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ExponentialBackoffRetry</span><span class="token punctuation">(</span><span class="token number">200000</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">//创建客户端(通过客户端创建Curator)</span>
    <span class="token comment">//retryPolicy 失败之后重试次数和时间</span>
    <span class="token class-name">CuratorFramework</span> client <span class="token operator">=</span> <span class="token class-name">CuratorFrameworkFactory</span><span class="token punctuation">.</span><span class="token function">builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">connectString</span><span class="token punctuation">(</span><span class="token string">"192.168.249.103:2181,192.168.249.104:2181,192.168.249.105:2181"</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">sessionTimeoutMs</span><span class="token punctuation">(</span><span class="token number">200000</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">connectionTimeoutMs</span><span class="token punctuation">(</span><span class="token number">200000</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">retryPolicy</span><span class="token punctuation">(</span>retry<span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>


    <span class="token comment">//客户端启动(开启连接)</span>
    client<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"zookeeper 客户端启动成功"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">//返回客户端</span>
    <span class="token keyword">return</span> client<span class="token punctuation">;</span>

<span class="token punctuation">}</span>

}

在这里插入图片描述

六、企业面试真题(面试重点)

6.1 选举机制

半数机制 ,超过半数的投票通过,即通过。
(1)第一次启动选举规则:
投票过半数时,服务器 id大的胜出
(2)第二次启动选举规则
EPOCH大的直接胜出(leader任期时的版本号
EPOCH相同,事务 id大的胜出
事务id相同,服务器 id大的胜出

6.2 生产集群安装多少zk合适

安装奇数台。
生产经验:

  • 10台 服务器: 3台 zk
  • 20台 服务器: 5台 zk
  • 100台 服务器: 11台 zk
  • 200台 服务器: 11台 zk

服务器台数多:好处,提高可靠性;坏处:提高通信延时

6.3 常用命令

ls、 get、 create、 delete


注意:源码部分留待以后进行学习完善。

总结

本篇文章仅仅是对Zookeeper进行了基础操作,对源码的解析还有待进行完善和学习。

posted @ 2022-10-28 21:19  wylja  阅读(40)  评论(0编辑  收藏  举报