Zookeeper3.5.7基础学习

文章目录

  • 一、Zookeeper入门
    • 1、概述
    • 2、特点
    • 3、数据结构
    • 4、应用场景
  • 二、Zookeeper 安装部署
    • 1、本地模式安装
      • 1.1 基础操作
      • 1.2 配置参数解读
    • 2、集群部署
      • 2.1 集群安装
      • 2.2 选举机制(面试重点)
      • 2.3 ZK 集群启动停止脚本
  • 三、ZK客户端相关操作
    • 1、客户端命令行操作
      • 1.1 命令行语法
      • 1.2 znode 节点数据信息
      • 1.3 节点类型(持久/短暂/有序号/无序号)
      • 1.4 节点删除与查看
    • 2、监听器原理
    • 3、客户端 API 操作
    • 4、客户端向服务端写数据流程
  • 四、ZK生产环境案例
    • 1、服务器动态上下线监听案例
      • 1.1 需求分析
      • 1.2 具体实现
      • 1.3 测试与分析
    • 2、ZooKeeper 分布式锁案例
      • 2.1 概述
      • 2.2 原生 Zookeeper 实现分布式锁案例
      • 2.3 Curator 框架实现分布式锁案例
  • 五、总结
    • 1、UI界面安装
    • 2、企业面试真题(面试重点)
      • 2.1 选举机制
      • 2.2 生产集群安装多少 zk 合适?
      • 2.3 常用命令

一、Zookeeper入门

官网:https://zookeeper.apache.org/

1、概述

Zookeeper 是一个开源的分布式的,为分布式框架提供协调服务的 Apache 项目

Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper就将负责通知已经在Zookeeper上注册的那些观察者做出相应的反应**。Zookeeper=文件系统+通知机制**

2、特点

  • Zookeeper:一个领导者(Leader),多个跟随者(Follower)组成的集群
  • 集群中只要有半数以上节点存活,Zookeeper集群就能正常服务。所以Zookeeper适合安装奇数台服务器
  • 全局数据一致:每个Server保存一份相同的数据副本,Client无论连接到哪个Server,数据都是一致的
  • 更新请求顺序执行,来自同一个Client的更新请求按其发送顺序依次执行
  • 数据更新原子性,一次数据更新要么成功,要么失败
  • 实时性,在一定时间范围内,Client能读到最新数据

3、数据结构

ZooKeeper 数据模型的结构与 Unix 文件系统很类似,整体上可以看作是一棵树,每个节点称做一个 ZNode。每一个 ZNode 默认能够存储 1MB 的数据,每个 ZNode 都可以通过其路径唯一标识

4、应用场景

提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等

  • 统一命名服务

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

  • 统一配置管理

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

  • 统一集群管理

分布式环境中,实时掌握每个节点的状态是必要的。可根据节点实时状态做出一些调整。ZooKeeper可以实现实时监控节点状态变化可将节点信息写入ZooKeeper上的一个ZNode。监听这个ZNode可获取它的实时状态变化。

  • 服务器动态上下线

客户端能实时洞察到服务器上下线的变化

  • 软负载均衡

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

二、Zookeeper 安装部署

1、本地模式安装

1.1 基础操作

# 首先自行安装jdk,这里我就继续在之前的hadoop集群上继续操作了
wget https://archive.apache.org/dist/zookeeper/zookeeper-3.5.7/apache-zookeeper-3.5.7-bin.tar.gz
tar -zxvf apache-zookeeper-3.5.7-bin.tar.gz -C /opt/module/
cd /opt/module/
mv apache-zookeeper-3.5.7-bin/ zookeeper-3.5.7/# ============配置修改=============
# 将/opt/module/zookeeper-3.5.7/conf 这个路径下的 zoo_sample.cfg 修改为 zoo.cfg
mv zoo_sample.cfg zoo.cfg
# 打开 zoo.cfg 文件,修改 dataDir 路径
vim zoo.cfg
# 修改如下内容
dataDir=/opt/module/zookeeper-3.5.7/zkData
# 在/opt/module/zookeeper-3.5.7/这个目录上创建 zkData 文件夹
mkdir zkData# ============操作 Zookeeper============
# 启动 Zookeeper
bin/zkServer.sh start
# 查看进程是否启动
jps
# 查看状态
bin/zkServer.sh status
# 启动客户端
bin/zkCli.sh
quit
# 停止 Zookeeper
bin/zkServer.sh stop

1.2 配置参数解读

vim zoo.cfg

# 通信心跳时间,Zookeeper服务器与客户端心跳时间,单位毫秒
tickTime=2000
# LF初始通信时限,Leader和Follower初始连接时能容忍的最多心跳数(tickTime的数量)
# 指定了Zookeeper集合中的Follower节点(从节点)在连接到Leader节点(主节点)时能够等待的时间量。在这个时间范围内,如果从节点不能连接到Leader节点,则从节点将放弃连接尝试
initLimit=10
# LF同步通信时限
# Leader和Follower之间通信时间如果超过syncLimit * tickTime,Leader认为Follwer死掉,从服务器列表中删除Follwer
syncLimit=5
# 保存Zookeeper中的数据
# 注意:默认的tmp目录,容易被Linux系统定期删除,所以一般不用默认的tmp目录。
dataDir=/opt/module/zookeeper-3.5.7/zkData
# 客户端连接端口,通常不做修改
clientPort=2181

2、集群部署

2.1 集群安装

# 在 hadoop102、hadoop103 和 hadoop104 三个节点上都部署 Zookeeper(这是之前hadoop集群用的)
# 在 hadoop102 解压 Zookeeper 安装包到/opt/module/目录下
tar -zxvf apache-zookeeper-3.5.7-bin.tar.gz -C /opt/module/
cd /opt/module/
mv apache-zookeeper-3.5.7-bin/ zookeeper-3.5.7/# ============配置修改=============
# 在/opt/module/zookeeper-3.5.7/这个目录上创建 zkData 文件夹
mkdir zkData
# 在/opt/module/zookeeper-3.5.7/zkData 目录下创建一个 myid 的文件
# 在文件中添加与 server 对应的编号(注意:上下不要有空行,左右不要有空格)
# 这里编写一个2,注意:添加 myid 文件,一定要在 Linux 里面创建,在 notepad++里面很可能乱码
vi myid# 拷贝配置好的 zookeeper 到其他机器上,分发脚本可以想见之前hadooop3.x学习笔记文章
xsync zookeeper-3.5.7
# 并分别在 hadoop103、hadoop104 上修改 myid 文件中内容为 3、4# ============配置zoo.cfg文件============
# 重命名/opt/module/zookeeper-3.5.7/conf 这个目录下的 zoo_sample.cfg 为 zoo.cfg
mv zoo_sample.cfg zoo.cfg
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# 配置参数解读
# server.A=B:C:D
# A 是一个数字,表示这个是第几号服务器;集群模式下配置一个文件myid,这个文件在 dataDir 目录下,这个文件里面有一个数据就是 A 的值,
# Zookeeper 启动时读取此文件,拿到里面的数据与 zoo.cfg 里面的配置信息比较从而判断到底是哪个 server。
# B 是这个服务器的地址;
# C 是这个服务器Follower 与集群中的 Leader 服务器交换信息的端口;
# D 是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的Leader,而这个端口就是用来执行选举时服务器相互通信的端口。# 同步zoo.cfg 配置文件
xsync zoo.cfg# ====================集群操作====================
# 分别三台机器启动Zookeeper
bin/zkServer.sh start
# 查看状态
bin/zkServer.sh status

2.2 选举机制(面试重点)

2.3 ZK 集群启动停止脚本

在 hadoop102 的/home/atguigu/bin 目录下创建脚本: vim zk.sh

#!/bin/bash
case $1 in
"start"){
for i in hadoop102 hadoop103 hadoop104
doecho ---------- zookeeper $i 启动 ------------ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh start"
done
};;
"stop"){
for i in hadoop102 hadoop103 hadoop104
doecho ---------- zookeeper $i 停止 ------------ ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh stop"
done
};;
"status"){
for i in hadoop102 hadoop103 hadoop104
doecho ---------- zookeeper $i 状态 ------------ ssh $i "/opt/module/zookeeper-3.5.7/bin/zkServer.sh status"
done
};;
esac
# 增加脚本执行权限
chmod u+x zk.sh
zk.sh start
zk.sh stop

三、ZK客户端相关操作

1、客户端命令行操作

1.1 命令行语法

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

1.2 znode 节点数据信息

# 查看当前znode中所包含的内容
ls / 
# 查看当前节点详细数据
ls -s /
  • czxid:创建节点的事务 zxid。每次修改ZooKeeper 状态都会产生一个ZooKeeper 事务 ID。事务 ID 是ZooKeeper 中所有修改总的次序。每次修改都有唯一的 zxid,如果 zxid1 小于 zxid2,那么zxid1 在 zxid2 之前发生。
  • ctime:znode 被创建的毫秒数(从 1970 年开始)
  • mzxid:znode 最后更新的事务zxid
  • mtime:znode 最后修改的毫秒数(从 1970 年开始)
  • pZxid:znode 最后更新的子节点zxid
  • cversion:znode 子节点变化号,znode 子节点修改次数
  • dataversion:znode 数据变化号
  • aclVersion:znode 访问控制列表的变化号
  • ephemeralOwner:如果是临时节点,这个是 znode 拥有者的 session id。如果不是临时节点则是 0
  • dataLength:znode 的数据长度
  • numChildren:znode 子节点数量

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

# 分别创建2个普通节点(永久节点 + 不带序号)
# 注意:创建节点时,要赋值
create /sanguo "diaochan"
create /sanguo/shuguo "liubei"
# 获得节点的值
get -s /sanguo
get -s /sanguo/shuguo# 创建带序号的节点(永久节点 + 带序号)
# 先创建一个普通的根节点/sanguo/weiguo
create /sanguo/weiguo "caocao"
# 创建带序号的节点
create -s /sanguo/weiguo/zhangliao "zhangliao"
# 重复编号会增加
create -s /sanguo/weiguo/zhangliao "zhangliao"# 创建短暂节点(短暂节点 + 不带序号 or 带序号)
# 创建短暂的不带序号的节点
create -e /sanguo/wuguo "zhouyu"
# 创建短暂的带序号的节点
create -e -s /sanguo/wuguo "zhouyu"
# 在当前客户端是能查看到的
ls /sanguo
# 退出当前客户端然后再重启客户端
quit
bin/zkCli.sh
# 再次查看根目录下短暂节点已经删除
ls /sanguo# 修改节点数据值
set /sanguo/weiguo "simayi"

1.4 节点删除与查看

# 删除节点
delete /sanguo/jin
# 递归删除节点
deleteall /sanguo/shuguo
# 查看节点状态
stat /sanguo

2、监听器原理

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

# 节点的值变化监听
# 在 hadoop104 主机上注册监听/sanguo 节点数据变化
get -w /sanguo
# 在 hadoop103 主机上修改/sanguo 节点的数据
# 观察 hadoop104 主机收到数据变化的监听
set /sanguo "xisi"
# 注意:在hadoop103再多次修改/sanguo的值,hadoop104上不会再收到监听。因为注册一次,只能监听一次。想再次监听,需要再次注册# 节点的子节点变化监听(路径变化)
# 在 hadoop104 主机上注册监听/sanguo 节点的子节点变化
ls -w /sanguo
# 在 hadoop103 主机/sanguo 节点上创建子节点
# create /sanguo/jin "simayi"
create /sanguo/jin "simayi"

3、客户端 API 操作

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

创建zookeeper工程,引入对应依赖

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

需要在项目的 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 

创建包名com.atguigu.zk,创建类名称zkClient

public class zkClient {// 注意:逗号左右不能有空格private String connectString = "hadoop102:2181,hadoop103:2181,hadoop104:2181";private int sessionTimeout = 2000;private ZooKeeper zkClient;//创建 ZooKeeper 客户端@Beforepublic void init() throws IOException {zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {@Overridepublic void process(WatchedEvent watchedEvent) {//                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();
//                }}});}//创建子节点@Testpublic void create() throws KeeperException, InterruptedException {// 参数 1:要创建的节点的路径; 参数 2:节点数据 ; 参数 3:节点权限 ;参数 4:节点的类型String nodeCreated = zkClient.create("/atguigu", "ss.avi".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);}//获取子节点并监听节点变化@Testpublic void getChildren() throws KeeperException, InterruptedException {List<String> children = zkClient.getChildren("/", true);for (String child : children) {System.out.println(child);}// 延时Thread.sleep(Long.MAX_VALUE);}@Testpublic void exist() throws KeeperException, InterruptedException {// 判断 Znode 是否存在Stat stat = zkClient.exists("/atguigu", false);System.out.println(stat==null? "not exist " : "exist");}
}

4、客户端向服务端写数据流程

写流程之写入请求直接发送给Leader节点(写完半数即可返回成功)

写流程之写入请求发送给follower节点

四、ZK生产环境案例

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

1.1 需求分析

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

1.2 具体实现

首先在集群上创建/serves节点 create /servers "servers"

在 Idea 中创建包名:com.atguigu.zkcase1,创建服务端DistributeServer

public class DistributeServer {private String connectString = "hadoop102:2181,hadoop103:2181,hadoop104:2181";private int sessionTimeout = 2000;private ZooKeeper zk;public static void main(String[] args) throws IOException, KeeperException, InterruptedException {DistributeServer server = new DistributeServer();// 1 获取zk连接server.getConnect();// 2 注册服务器到zk集群server.regist(args[0]);// 3 启动业务逻辑(睡觉)server.business();}private void business() throws InterruptedException {Thread.sleep(Long.MAX_VALUE);}private void regist(String hostname) throws KeeperException, InterruptedException {String create = zk.create("/servers/"+hostname, hostname.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);System.out.println(hostname +" is online") ;}private void getConnect() throws IOException {zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {@Overridepublic void process(WatchedEvent watchedEvent) {}});}
}

创建客户端DistributeClient

public class DistributeClient {private String connectString = "hadoop102:2181,hadoop103:2181,hadoop104:2181";private int sessionTimeout = 2000;private ZooKeeper zk;public static void main(String[] args) throws IOException, KeeperException, InterruptedException {DistributeClient client = new DistributeClient();// 1 获取zk连接client.getConnect();// 2 监听/servers下面子节点的增加和删除client.getServerList();// 3 业务逻辑(睡觉)client.business();}private void business() throws InterruptedException {Thread.sleep(Long.MAX_VALUE);}private void getServerList() throws KeeperException, InterruptedException {List<String> children = zk.getChildren("/servers", true);ArrayList<String> servers = new ArrayList<>();for (String child : children) {byte[] data = zk.getData("/servers/" + child, false, null);servers.add(new String(data));}// 打印System.out.println(servers);}private void getConnect() throws IOException {zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {@Overridepublic void process(WatchedEvent watchedEvent) {try {getServerList();} catch (KeeperException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}});}
}

1.3 测试与分析

# 首先启动客户端
# 然后可以进行命令行的测试
create -e -s /servers/hadoop102 "hadoop102"# 最后启动服务端,这里需要进行设置,否则同一时刻只能启动一个
# 点击 Edit Configurations,在弹出的窗口中(Program arguments)输入想启动的主机,例如,hadoop102
# 然后进行启动注册

2、ZooKeeper 分布式锁案例

2.1 概述

分布式锁的概念可以参考:几种分布式锁详解

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

public class DistributedLock {private final String connectString = "hadoop102:2181,hadoop103:2181,hadoop104:2181";private final int sessionTimeout = 2000;private final ZooKeeper zk;private CountDownLatch connectLatch = new CountDownLatch(1);private CountDownLatch waitLatch = new CountDownLatch(1);private String waitPath;private String currentMode;public DistributedLock() throws IOException, InterruptedException, KeeperException {// 获取连接zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {@Overridepublic void process(WatchedEvent watchedEvent) {// connectLatch  如果连接上zk  可以释放if (watchedEvent.getState() == Event.KeeperState.SyncConnected){connectLatch.countDown();}// waitLatch  需要释放if (watchedEvent.getType()== Event.EventType.NodeDeleted && watchedEvent.getPath().equals(waitPath)){waitLatch.countDown();}}});// 等待zk正常连接后,往下走程序connectLatch.await();// 判断根节点/locks是否存在Stat stat = zk.exists("/locks", false);if (stat == null) {// 创建一下根节点zk.create("/locks", "locks".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);}}// 对zk加锁public void zklock() {// 创建对应的临时带序号节点try {currentMode = zk.create("/locks/" + "seq-", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);// wait一小会, 让结果更清晰一些Thread.sleep(10);// 判断创建的节点是否是最小的序号节点,如果是获取到锁;如果不是,监听他序号前一个节点List<String> children = zk.getChildren("/locks", false);// 如果children 只有一个值,那就直接获取锁; 如果有多个节点,需要判断,谁最小if (children.size() == 1) {return;} else {Collections.sort(children);// 获取节点名称 seq-00000000String thisNode = currentMode.substring("/locks/".length());// 通过seq-00000000获取该节点在children集合的位置int index = children.indexOf(thisNode);// 判断if (index == -1) {System.out.println("数据异常");} else if (index == 0) {// 就一个节点,可以获取锁了return;} else {// 需要监听  他前一个节点变化waitPath = "/locks/" + children.get(index - 1);zk.getData(waitPath,true,new Stat());// 等待监听waitLatch.await();return;}}} catch (KeeperException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}// 解锁public void unZkLock() {// 删除节点try {zk.delete(this.currentMode,-1);} catch (InterruptedException e) {e.printStackTrace();} catch (KeeperException e) {e.printStackTrace();}}}

测试代码

public class DistributedLockTest {public static void main(String[] args) throws InterruptedException, IOException, KeeperException {final  DistributedLock lock1 = new DistributedLock();final  DistributedLock lock2 = new DistributedLock();new Thread(new Runnable() {@Overridepublic void run() {try {lock1.zklock();System.out.println("线程1 启动,获取到锁");Thread.sleep(5 * 1000);lock1.unZkLock();System.out.println("线程1 释放锁");} catch (InterruptedException e) {e.printStackTrace();}}}).start();new Thread(new Runnable() {@Overridepublic void run() {try {lock2.zklock();System.out.println("线程2 启动,获取到锁");Thread.sleep(5 * 1000);lock2.unZkLock();System.out.println("线程2 释放锁");} catch (InterruptedException e) {e.printStackTrace();}}}).start();}
}

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

https://curator.apache.org/index.html

原生的 Java API 开发存在的问题会话,连接是异步的,需要自己去处理。比如使用 CountDownLatch;Watch 需要重复注册,不然就不能生效;开发的复杂性还是比较高的;不支持多节点删除和创建。需要自己去递归

Curator 是一个专门解决分布式锁的框架,解决了原生 JavaAPI 开发分布式遇到的问题,首先添加依赖

<dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>4.3.0</version>
</dependency>
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.3.0</version>
</dependency>
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-client</artifactId><version>4.3.0</version>
</dependency>

代码实现

public class CuratorLockTest {public static void main(String[] args) {// 创建分布式锁1InterProcessMutex lock1 = new InterProcessMutex(getCuratorFramework(), "/locks");// 创建分布式锁2InterProcessMutex lock2 = new InterProcessMutex(getCuratorFramework(), "/locks");new Thread(new Runnable() {@Overridepublic void run() {try {lock1.acquire();System.out.println("线程1 获取到锁");lock1.acquire();System.out.println("线程1 再次获取到锁");Thread.sleep(5 * 1000);lock1.release();System.out.println("线程1 释放锁");lock1.release();System.out.println("线程1  再次释放锁");} catch (Exception e) {e.printStackTrace();}}}).start();new Thread(new Runnable() {@Overridepublic void run() {try {lock2.acquire();System.out.println("线程2 获取到锁");lock2.acquire();System.out.println("线程2 再次获取到锁");Thread.sleep(5 * 1000);lock2.release();System.out.println("线程2 释放锁");lock2.release();System.out.println("线程2  再次释放锁");} catch (Exception e) {e.printStackTrace();}}}).start();}private static CuratorFramework getCuratorFramework() {ExponentialBackoffRetry policy = new ExponentialBackoffRetry(3000, 3);CuratorFramework client = CuratorFrameworkFactory.builder().connectString("hadoop102:2181,hadoop103:2181,hadoop104:2181").connectionTimeoutMs(2000).sessionTimeoutMs(2000).retryPolicy(policy).build();// 启动客户端client.start();System.out.println("zookeeper 启动成功");return client;}
}

五、总结

1、UI界面安装

参考:Centos7安装zookeeper和Web UI

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

2.1 选举机制

半数机制,超过半数的投票通过,即通过

第一次启动选举规则:

  • 投票过半数时,服务器 id 大的胜出

第二次启动选举规则:

  • EPOCH 大的直接胜出
  • EPOCH 相同,事务 id 大的胜出
  • 事务 id 相同,服务器 id 大的胜出

2.2 生产集群安装多少 zk 合适?

安装奇数台。服务器台数多:好处,提高可靠性;坏处:提高通信延时。生产经验:

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

2.3 常用命令

ls、get、create、delete

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/651152.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【第七在线】数字化转型:智能商品计划管理的核心要素

随着科技的快速发展&#xff0c;数字化转型已经成为企业适应市场变化、提高运营效率的必由之路。尤其在服装行业&#xff0c;快速的市场反应和精准的供应链管理显得尤为重要。其中&#xff0c;智能商品计划管理作为数字化转型的核心要素&#xff0c;正在重塑整个行业的竞争格局…

【RH850U2A芯片】Reset Vector和Interrupt Vector介绍

目录 前言 正文 1. 什么是Reset Vector 1.1 S32K144芯片的Reset Vector 1.2 RH850芯片的Reset Vector 2. 什么是Interrupt Vector 2.1 S32K144芯片的Interrupt Vector 2.2 RH850芯片的Interrupt Vector 3. Reset Vector等价于Interrupt Vector吗 4. 总结 前言 最近在…

$monitor和$strobe都看的是啥

注&#xff1a;本文来自硅芯思见 在编写测试平时&#xff0c;经常会用到$monitor和$strobe监测某些信号&#xff0c;并且使用格式上与$display比较类似&#xff0c;但是它们之间还是存在差异的&#xff0c;它们在当前仿真时间槽&#xff08;time-slot&#xff09;中被执行的区间…

常见电源电路(LDO、非隔离拓扑和隔离拓扑结构)

一、常见电路元件和符号 二、DC-DC转换器 DC-DC转换器&#xff1a;即直流-直流转换器&#xff0c;分为三类&#xff1a;①线性调节器&#xff1b;②电容性开关解调器&#xff1b;③电感性开关调节器&#xff1b; 2.1线性稳压器&#xff08;LDO&#xff09; 2.1.1 NMOS LDO…

如何将前后端分离(vue2+SpringBoot)项目部署到腾讯云服务器

如何将前后端分离&#xff08;vue2SpringBoot&#xff09;项目部署到腾讯云服务器 目录 如何将前后端分离&#xff08;vue2SpringBoot&#xff09;项目部署到腾讯云服务器 1、在选中目录地下新建2个文件夹 2、将打包好的前端项目和后端jar包上传到相应的目录下 3、将路径切…

Gin 应用多实例部署session问题、session参数与刷新

文章目录 一、Gin Session 存储的实现方案二、memstore&#xff1a;基于内存的实现2.1 基本使用2.2 关键参数 三、使用redis&#xff1a;多实例部署3.1 使用redis优势3.2 基本使用 四、信息安全的三个核心概念五、Gin Session 参数5.1 参数介绍 六、Session 自动刷新 一、Gin S…

语图奇缘:林浩然与杨凌芸的哲学漫画大冒险

语图奇缘&#xff1a;林浩然与杨凌芸的哲学漫画大冒险 Language Odyssey: The Philosophical Comic Adventure of Lin Haoran and Yang Lingyun 在一个充满逻辑谜题和言语陷阱的城市——逻言市&#xff0c;住着两位热衷于探索语言奥秘的年轻人&#xff0c;林浩然和杨凌芸。林浩…

一篇文章带你了解C++中隐含的this指针

文章目录 一、this指针的引出二、this指针的特性【面试题】 一、this指针的引出 我们先来定义一个日期类Date&#xff0c;下面这段代码执行的结果是什么呢&#xff1f; class Date { public:void Init(int year, int month, int day){_year year;_month month;_day day;}v…

2024新版68套Axure RP大数据可视化大屏模板及通用组件+PSD源文件

Axure RP数据可视化大屏模板及通用组件库2024新版重新制作了这套新的数据可视化大屏模板及通用组件库V2版。新版本相比于V1版内容更加丰富和全面&#xff0c;但依然秉承“敏捷易用”的制作理念&#xff0c;这套作品也同样延续着我们对细节的完美追求&#xff0c;整个设计制作过…

【PythonRS】Rasterio库安装+基础函数使用教程

Rasterio是一个Python库&#xff0c;专门用于栅格数据的读写操作。它支持多种栅格数据格式&#xff0c;如GeoTIFF、ENVI和HDF5&#xff0c;为处理和分析栅格数据提供了强大的工具。RasterIO适用于各种栅格数据应用&#xff0c;如卫星遥感、地图制作等。通过RasterIO&#xff0c…

Two-factor authentication (2FA) is required for your GitHub account解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

SkyWalking介绍与使用docker-compose部署服务

一、Skywalking概述 1、Skywalking介绍 Skywalking是分布式系统的应用程序性能监视工具,专为微服务,云原生架构和基于容器(Docker,K8S,Mesos)架构而设计,它是一款优秀的APM(Application Performance Management)工具,包括了分布式追踪,性能指标分析和服务依赖分析等…

gitee仓库使用中的警告

当 Git 执行 git pull 命令时&#xff0c;有时候会出现类似下面的警告信息&#xff1a; warning: ----------------- SECURITY WARNING ---------------- warning: | TLS certificate verification has been disabled! | warning: ------------------------------------------…

网络安全03---Nginx 解析漏洞复现

目录 一、准备环境 二、实验开始 2.1上传压缩包并解压 2.2进入目录&#xff0c;开始制作镜像 2.3可能会受之前环境影响&#xff0c;删除即可 ​编辑 2.4制作成功结果 2.5我们的环境一个nginx一个php 2.6访问漏洞 2.7漏洞触发结果 2.8上传代码不存在漏洞 2.9补充&#…

【蓝桥杯冲冲冲】旅行计划

蓝桥杯备赛 | 洛谷做题打卡day18 文章目录 蓝桥杯备赛 | 洛谷做题打卡day18旅行计划题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示题解代码我的一些话 旅行计划 题目描述 Kira酱要去一个国家旅游。这个国家有 N N N 个城市&#xff0c;编号为 1 1 1 至 N N…

SpringSecurity(16)——OAuth2客户端授权模式

工作流程 基本使用 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId><version>2.3.12.RELEASE</version> </dependency> <dependency><groupId>…

大数据Doris(五十九):SQL函数之字符串函数(三)

文章目录 SQL函数之字符串函数(三) 一、​​​​​​​NULL_OR_EMPTY (VARCHAR str)

力扣1312. 让字符串成为回文串的最少插入次数

动态规划 思路&#xff1a; 通过插入字符构造回文串&#xff0c;要想插入次数最少&#xff0c;可以将字符串 s 的逆序 s 进行比较找出最长公共子序列&#xff1b;可以先分析&#xff0c;字符串 s 通过插入得到回文串 ps&#xff0c;其中间的字符应该不会变化&#xff1a; 若 s…

基于springboot+vue的校园资料分享平台(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目背景…

qt学习:实战 http请求获取qq的吉凶

目录 利用的api是 聚合数据 的qq号码测吉凶 编程步骤 配置ui界面 添加头文件&#xff0c;定义网络管理者和http响应槽函数 在界面的构造函数里创建管理者对象&#xff0c;关联http响应槽函数 实现按钮点击事件 实现槽函数 效果 利用的api是 聚合数据 的qq号码测吉凶 先…