【Zookeeper】学习笔记(二)

news/2024/11/29 1:40:24/

Zookeeper学习笔记

  • 四、客户端命令
    • 4.1、新增节点
    • 4.2、查询节点信息
    • 4.3、节点类型
    • 4.4、更新节点
    • 4.5、删除节点
    • 4.6、监听器
  • 五、SpringBOOT整合Zookeeper
  • 六、写数据流程
    • 6.1、写流程之写入请求直接发送给Leader节点
    • 6.2、写流程之写入请求发送给follower节点
  • 七、服务器动态上下线监听
    • 7.1、案例
  • 八、分布式锁
    • 8.1、分析
    • 8.1、案例
  • 九、其他
    • 9.1、生产集群安装多少k合适

四、客户端命令

在bin目录下 集群客户端启动命令

./zkCli.sh -server 192.168.3.34:2181

4.1、新增节点

命令格式:

# -s 为有序节点, -e 为临时节点
create [-s] [-e] path data

创建持久化节点并写入数据:

# 创建 hadoop节点,内容为123456
create /hadoop "123456"
# 读取节点内容
get /hadoop

创建持久化有序节点。此时创建出来的节点名称为:指定的节点名+自增序号:

#创建出来的节点名称为:指定的节点名+自增序号:# 此时创建出来的节点名称为/a0000000001
create -s /a "a"# 再创建/b时,节点名称为/b0000000002
create -s /b "b"

创建临时节点:

create -e /tmp "tmp"# 创建完之后,通过get /tmp可以查到
get /tmp# 使用quit退出当前会话
quit# 重新打开zkCli,get /tmp 找不到该节点
get /tmp

创建临时有序节点,可用于分布式锁:

# 创建的临时节点:/t0000000004
create -s -e /t "tt"

4.2、查询节点信息

节点数据信息

ls -s /

节点属性说明:

  • cZxid:数据节点创建时的事务ID
  • ctime:数据节点创建时的时间
  • mZxid:数据节点最后一次更新时的事务ID
  • pZxid:数据节点最后一次更新时的时间
  • cversion:子节点的更改次数
  • dataVersion:节点数据的更改次数
  • aclVersion:节点的ACL的更改次数
  • ephemeralOwner:如果节点是临时节点,则表示创建该节点的会话sessionID。如果节点是持久节点,则该属性值为0
  • dataLength:数据内容的长度
    numChildren:数据节点当前的子节点个数

4.3、节点类型

持久(Persistent):客户端和服务器端断开连接后,创建的节点不删除
短暂(Ephemeral):客户端和服务器端断开连接后,创建的节点自己删除

  1. 持久化目录节点
    客户端与Zookeeper断开连接后,该节点依旧存在
  2. 持久化顺序编号目录节点
    客户端与Zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号由父节点维护
  3. 临时目录节点
    客户端与Zookeeper断开连接后,该节点被删除
  4. 临时顺序编号目录节点
    客户端与Zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号。让天下漫有难学的技

4.4、更新节点

set /hadoop "1234"

4.5、删除节点

delete /hadoop

4.6、监听器

1、监听原理详解

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

在这里插入图片描述

监听节点数据的变化

get path [watch]
# 注册一次,只能监听一次。想再次监听,需要再次注册。

监听子节点增减的变化

ls path [watch]

五、SpringBOOT整合Zookeeper

SpringBOOT整合Zookeeper

六、写数据流程

6.1、写流程之写入请求直接发送给Leader节点

在这里插入图片描述

  1. 客户端想服务器leader写入数据
  2. leader向slave1写入
  3. slave1写完向leader发送ack表示自己写入完成
  4. 只要超过半数,就可以应答了 leader向客户端发送ack
  5. leader向slave2写入
  6. slave2写完向leader发送ack表示自己写入完成

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

在这里插入图片描述

  1. 客户端想服务器slave1写入数据
  2. slave1没有写入权限、将数据转发给leader
  3. leader写入后再向slave1写入
  4. slave1写完向leader发送ack表示自己写入完成
  5. 只要超过半数,就可以应答了 leader向客户端发送ack
  6. leader向slave2写入
  7. slave2写完向leader发送ack表示自己写入完成

七、服务器动态上下线监听

在这里插入图片描述

7.1、案例

先在客户端创建一个结点
create /servers "servers"

Server端 (创建3个 在 server.regist(“zk1”)改成不同的名字zk1、zk2、zk3)

import org.apache.zookeeper.*;
import java.io.IOException;public class DistributeServer01 {//,分割不能有空格 在程序里写connectString不可使用ip,必须使用主机名private String connectString = "master:2181,slave1:2181,slave2:2181";//超时时间private int sessionTimeout = 2000;//zk客户端private ZooKeeper zkClient;public static void main(String[] args) throws IOException, InterruptedException, KeeperException {DistributeServer01 server=new DistributeServer01();//1.获取zk连接server.getConnect();//2.注册服务器到zk集群server.regist("zk1");//3.启动业务逻辑(睡觉)server.business();}private void business() throws InterruptedException {Thread.sleep(Long.MAX_VALUE);}private void regist(String hostname) throws InterruptedException, KeeperException {String s = zkClient.create("/servers/", hostname.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);System.out.println(hostname+"已经上线");}private void getConnect() throws IOException {zkClient= new ZooKeeper(connectString, sessionTimeout, new Watcher() {@Overridepublic void process(WatchedEvent watchedEvent) {}});}
}

Client端

import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;public class DistributeClient {//,分割不能有空格 在程序里写connectString不可使用ip,必须使用主机名private String connectString = "master:2181,slave1:2181,slave2:2181";//超时时间private int sessionTimeout = 2000;//zk客户端private ZooKeeper zkClient;public static void main(String[] args) throws IOException, InterruptedException, KeeperException {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 InterruptedException, KeeperException {List<String> children = zkClient.getChildren("/servers", true);ArrayList<String> servers = new ArrayList<>();for (String s:children){try {byte[] data = zkClient.getData("/servers/" + s, false, null);servers.add(new String(data, "utf-8"));}catch (Exception e){}}System.out.println(servers);}private void getConnect() throws IOException {zkClient= new ZooKeeper(connectString, sessionTimeout, new Watcher() {@Overridepublic void process(WatchedEvent watchedEvent) {try {getServerList();} catch (InterruptedException e) {e.printStackTrace();} catch (KeeperException e) {e.printStackTrace();}}});}
}

逐步启动DistributeServer01 、DistributeServer02、DistributeServer013 启动一个看一下DistributeClient 的控制台
在这里插入图片描述

八、分布式锁

8.1、分析

  1. 接收到请求后,在/locks节点下创建一个临时顺序节点
  2. 判断自己是不是当前节点下最小的节点:是,获取到锁;不是,对前一个节点进行监听
  3. 获取到锁,处理完业务后,delete节点释放锁,然后下面的节点将收到通知,重复第二步判断
    在这里插入图片描述

8.1、案例

DistributeLock

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;public class DistributeLock {//,分割不能有空格 在程序里写connectString不可使用ip,必须使用主机名private String connectString = "master:2181,slave1:2181,slave2:2181";//超时时间private int sessionTimeout = 2000;//zk客户端private ZooKeeper zkClient;private CountDownLatch countDownLatch=new CountDownLatch(1);private CountDownLatch waitDownLatch=new CountDownLatch(1);//前一个结点的路径private String waitPath;private String currentMode;public  DistributeLock() throws IOException, InterruptedException, KeeperException {//获取连接zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {@Overridepublic void process(WatchedEvent watchedEvent) {// connectLatch如果连接上zk可以释放if (watchedEvent.getState() == Event.KeeperState.SyncConnected){countDownLatch.countDown();}// waitLatch需要释放if (watchedEvent.getType()==Event.EventType.NodeDeleted && watchedEvent.getPath().equals(waitPath)){waitDownLatch.countDown();}}});//等待zk连接成功countDownLatch.await();//判断根节点locks是否存在Stat exists = zkClient.exists("/locks", false);if(exists==null){//创建根节点zkClient.create("/locks","locks".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);}}//对zk加锁public  void zkLock(){//创建临时带序号结点try {currentMode = zkClient.create("/locks/" + "seq-", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);//判断创建的结点是否是最小的结点 是获取锁,如果不是监听前一个结点List<String> children = zkClient.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);zkClient.getData(waitPath,true,null);//等待监听waitDownLatch.await();return;}}} catch (KeeperException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}//对zk解锁public  void UnzkLock(){//删除结点try {zkClient.delete(currentMode,-1);} catch (InterruptedException e) {e.printStackTrace();} catch (KeeperException e) {e.printStackTrace();}}
}

DistributeLockTest

import org.apache.zookeeper.KeeperException;
import java.io.IOException;
public class DistributeLockTest {public static void main(String[] args) throws IOException, InterruptedException, KeeperException {final DistributeLock distributeLock1 = new DistributeLock();final DistributeLock distributeLock2 = new DistributeLock();new Thread(()->{try {distributeLock1.zkLock();System.out.println("aaa线程获取锁");Thread.sleep(5000);distributeLock1.UnzkLock();System.out.println("aaa线程释放锁");} catch (InterruptedException e) {e.printStackTrace();}},"aaa").start();new Thread(()->{try {distributeLock2.zkLock();System.out.println("bbb线程获取锁");Thread.sleep(5000);distributeLock2.UnzkLock();System.out.println("bbb线程释放锁");} catch (InterruptedException e) {e.printStackTrace();}},"bbb").start();}
}

九、其他

9.1、生产集群安装多少k合适

安装奇数台
生产经验:

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

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


http://www.ppmy.cn/news/2525.html

相关文章

Spring从入门到精通(二)

文章目录1.动态代理1.1 概念1.2 jdk动态代理&#xff08;重点&#xff09;1.3 基于子类的动态代理&#xff08;了解&#xff09;2.AOP2.1 概念2.2 springAop — 基于AspectJ技术2.2.1 AspectJ使用&#xff08;XML&#xff09;2.2.2 AspectJ使用&#xff08;注解开发&#xff09…

c语言---指针进阶(2)--玩转指针

今天内容不多&#xff0c;但都是精华。 1.数组参数和指针参数 2.函数指针 2.1笔试题 3.函数指针数组 1.数组参数和指针参数 例1&#xff1a;一维数组传参 void test(int arr[]) {} void test(int arr[10]) {} void test(int *arr) {}void test2(int *arr2[20]) {} void …

Verilog语法之generate for、generate if、generate case

0、前言 Verilog-2005中有3个generate 语句可以用来很方便地实现重复赋值和例化&#xff08;generate for&#xff09;或根据条件选择性地进行编译&#xff08;generate if和generate case&#xff09;等功能。接下来就一起看下这3个语句的应用场景和应用方法吧。 1、generate …

Laravel 某个固定数据排序在列表顶部sql查询(自定义排序)

业务需要列表中某个固定用户数据处于列表顶部&#xff0c;该用户author状态有多个值&#xff08;例如&#xff1a;1-999&#xff09;&#xff0c;需要置于顶部的为中间的某个值&#xff08;例如&#xff1a;author68&#xff09; 实现方式&#xff1a; 1、判断 author的值是不…

Web服务器通信原理

电脑&#xff1a; Windows 系统 微软开发 闭源 Linux 开源的系统&#xff08;无数的子系统&#xff09; Mac os 苹果系统 WEB 安全 > WEB的安全&#xff08;网站安全&#xff09; 服务器&#xff1a; 就是一台不关机的电…

Properties类的使用

Properties类是一个配置文件类&#xff0c;主要作用就是用来封装配置文件&#xff0c;将配置文件加载成为一个Properties对象。 注意&#xff1a;Properties类一般用来加载 .properties配置文件 首先看一下.properties配置文件的样子 driverClassNamecom.mysql.cj.jdbc.Drive…

LeetCode刷题复盘笔记—一文搞懂完全背包之139. 单词拆分问题(动态规划系列第十六篇)

今日主要总结一下动态规划完全背包的一道题目&#xff0c;139. 单词拆分 题目&#xff1a;139. 单词拆分 Leetcode题目地址 题目描述&#xff1a; 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。 注意&#xff1a;…

字符串处理【AC自动机】 - 原理 AC自动机详解

字符串处理【AC自动机】 - 原理 AC自动机详解 AC自动机&#xff08;Aho-Corasick automaton&#xff09;在1975年产生于贝尔实验室&#xff0c;是著名的多模匹配算法。 学习AC自动机&#xff0c;要有KMP和Trie&#xff08;字典树&#xff09;的基础知识。 KMP是单模匹配算法&a…