Zookeeper学习笔记
Zookeeper入门
Zookeeper 是一个开源的分布式的,为分布式框架提供协调服务的Apache 项目。
Zookeeper工作机制
Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper就将负责通知已经在Zookeeper上注册的那些观察者做出相应的反应。
Zookeeper特点
1)Zookeeper:一个领导者(Leader),多个跟随者(Follower)组成的集群。
2)集群中只要有半数以上节点存活,Zookeeper集群就能正常服务。所以Zookeeper适合安装奇数台服务器。
3)全局数据一致:每个Server保存一份相同的数据副本,Client无论连接到哪个Server,数据都是一致的。
4)更新请求顺序执行,来自同一个Client的更新请求按其发送顺序依次执行。
5)数据更新原子性,一次数据更新要么成功,要么失败。
6)实时性,在一定时间范围内,Client能读到最新数据。
数据结构
ZooKeeper 数据模型的结构与Unix 文件系统很类似,整体上可以看作是一棵树,每个节点称做一个ZNode。每一个ZNode 默认能够存储1MB 的数据,每个ZNode 都可以通过其路径唯一标识。
应用场景
提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等。
统一命名服务
在分布式环境下,经常需要对应用/服务进行统一命名,便于识别。
统一配置管理
- 分布式环境下,配置文件同步非常常见
- 一般要求一个集群中,所有节点的配置信息一致,比如Kafka集群
- 对配置文件修改,同步到各个节点
- 配置管理交给Zookeeper实现
- 可将配置信息写入ZooKeeper上的一个Znode
- 各个客户端服务器监听这个Znode
- 一旦Znode中的数据被修改,ZooKeeper将通知各个客户端服务器
统一集群管理
- 分布式环境中,实时掌握每个节点的状态是必要的
- 可根据节点实时状态做出一些调整
- ZooKeeper可以实现实时监控节点状态变化
- 可将节点信息写入ZooKeeper上的一个ZNode
- 监听Znode可获取它的实时的状态变化
服务器动态上下线
客户端能实时洞察到服务器上下线的变化
软负载均衡
在Zookeeper中记录每台服务器的访问数,让访问数最少的服务器去处理最新的客户端请求
下载安装
配置参数解读
Zookeeper中的配置文件zoo.cfg中参数含义解读如下:
tickTime = 2000:通信心跳时间,Zookeeper服务器与客户端心跳时间,单位毫秒
initLimit = 10:LF初始通信时限
Leader和Follower初始连接时能容忍的最多心跳数(tickTime的数量)
syncLimit = 5:LF同步通信时限
Leader和Follower之间通信时间如果超过syncLimit * tickTime,Leader认为Follwer死掉,从服务器列表中删除Follwer
dataDir:保存Zookeeper中的数据
注意:默认的tmp目录,容易被Linux系统定期删除,所以一般不用默认的tmp目录。
clientPort = 2181:客户端连接端口,通常不做修改。
客户端命令行操作
命令基本语法 | 功能描述 |
---|---|
help | 显示所有操作命令 |
ls path | ls 查看当前znode的子节点 -w 监听子节点变化 -s附加次级信息 |
create | 普通创建 -s 含有序列 -e临时(重启或者超时消失) |
get path | 获得节点的值可监听 -w 监听节点内容变化 -s 附加次级信息 |
set | 设置节点的具体值 |
stat | 查看节点状态 |
delete | 删除节点 |
deleteall | 递归删除节点 |
znode节点数据信息
查看当前znode中所包含的内容
[zk: hadoop102 :2181(CONNECTED) 0] ls
[zookeeper]
查看当前节点详细数据
[zk: hadoop102 :2181(CONNECTED) 5] ls s /
[zookeeper]cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1
(1 czxid 创建节点的事务 zxid
每次修改ZooKeeper状态都会 产生一个 ZooKeeper事务 ID。事务 ID是 ZooKeeper中所有修改总的次序。每 次 修改都有唯一的 zxid,如果 zxid1小于 zxid2,那么 zxid1在 zxid2之前发生。
(2 ctime znode被创建的毫秒数(从 1970年开始)
(3 mzxid znode最后更新的事务 zxid
(4 mtime znode最后修改的毫秒数(从 1970年开始)
(5 pZxid znode最后更新的子节点 zxid(6)cversion:znode 子节点变化号,znode 子节点修改次数
(7)dataversion:znode 数据变化号
(8)aclVersion:znode 访问控制列表的变化号
(9)ephemeralOwner:如果是临时节点,这个是znode 拥有者的session id。如果不是
临时节点则是0。
(10)dataLength:znode 的数据长度
(11)numChildren:znode 子节点数量
节点类型(持久/短暂/有序号/无序号)
监听器原理
客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、节点删除、子目录节点增加删除)时,ZooKeeper 会通知客户端。监听机制保证ZooKeeper 保存的任何的数据的任何改变都能快速的响应到监听了该节点的应用程序。
客户端API操作
添加pom文件
<properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>RELEASE</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</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><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></dependencies>
需要在项目的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
@Slf4j
public class ZKClient {// 注意:逗号左右不能有空格private static final String CONNECTSTRING = "127.0.0.1:2181";private static final int SESSIONTIMEOUT = 2000;private ZooKeeper zookeeper;// 创建 ZooKeeper客户端@Beforepublic void init() throws IOException {zookeeper = new ZooKeeper(CONNECTSTRING, SESSIONTIMEOUT, watchedEvent -> {log.info("---------------------------------");List<String> children;try {children = zookeeper.getChildren("/", true);for (String child : children) {log.info(child);}log.info("---------------------------------");} catch (Exception e) {e.printStackTrace();}});}// 创建子节点@Testpublic void create() throws KeeperException, InterruptedException {zookeeper.create("/kangxiaozhuang", "ss.avi".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);}// 获取子节点并监听节点变化@Testpublic void getChildren() throws KeeperException, InterruptedException {List<String> children = zookeeper.getChildren("/", true);for (String child : children) {log.info(child);}// 延时Thread.sleep(5000);}// 节点是否存在@Testpublic void exist() throws KeeperException, InterruptedException {Stat stat = zookeeper.exists("/atguigu", false);log.info(stat == null ? "not exist " : "exist");}
}
客户端向服务端写数据流程
写流程之写入请求直接发送给Leader节点
写流程之写入请求发送给follower节点
服务器动态上下线监听案例
某分布式系统中,主节点可以有多台,可以动态上下线,任意一台客户端都能实时感知到主节点服务器的上下线
先在集群上创建/servers 节点
create /servers "servers"
服务器端向Zookeeper注册代码
package com.zhuang.zookeeper.case1;import lombok.extern.slf4j.Slf4j;
import org.apache.zookeeper.*;
import java.io.IOException;/*** 服务器动态上下线服务端*/
@Slf4j
public class DistributeServer {private static final String CONNECTSTRING = "127.0.0.1:2181";private static final 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("hadoop101");// 3 启动业务逻辑(睡觉)server.business();}// 业务功能private void business() throws InterruptedException {Thread.sleep(Long.MAX_VALUE);}// 注册服务器private void regist(String hostname) throws KeeperException, InterruptedException {zk.create("/servers/" + hostname, hostname.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);log.info(hostname + " is online");}private void getConnect() throws IOException {zk = new ZooKeeper(CONNECTSTRING, SESSIONTIMEOUT, watchedEvent -> {});}
}
DistributeClient客户端代码
package com.zhuang.zookeeper.case1;import lombok.extern.slf4j.Slf4j;
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;/*** 服务器动态上下线客户端*/
@Slf4j
public class DistributeClient {private static final String CONNECTSTRING = "127.0.0.1:2181";private static final 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(Integer.MAX_VALUE);}// 获取服务器列表信息private void getServerList() throws KeeperException, InterruptedException {// 1 获取服务器 子节点信息,并且对父节点进行监听List<String> children = zk.getChildren("/servers", true);// 2 存储服务器信息列表ArrayList<String> servers = new ArrayList<>();// 3 遍历所有节点,获取节点中的主机名称信息for (String child : children) {byte[] data = zk.getData("/servers/" + child, false, null);servers.add(new String(data));}// 打印log.info(String.valueOf(servers));}private void getConnect() throws IOException {zk = new ZooKeeper(CONNECTSTRING, SESSIONTIMEOUT, watchedEvent -> {try {getServerList();} catch (Exception e) {e.printStackTrace();}});}
}
ZooKeeper分布式锁案例
什么叫做分布式锁呢?比如说"进程 1"在使用该资源的时候,会先去获得锁, ,"进程 1"获得锁以后会对该资源保持独占,这样其他进程就无法访问该资源,"进程1"用完该资源以后就将锁释放掉,让其他进程来获得锁,那么通过这个锁机制,我们就能保证了分布式系统中多个进程能够有序的访问该临界资源。那么我们把这个分布式环境下的这个锁叫作分布式锁。
分布式锁实现
package com.zhuang.zookeeper.case2;import lombok.extern.slf4j.Slf4j;
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;@Slf4j
public class DistributedLock {// zookeeper server 列表private static final String CONNECTSTRING = "127.0.0.1:2181";// 超时时间private static final int SESSIONTIMEOUT = 2000;private final ZooKeeper zk;private final CountDownLatch connectLatch = new CountDownLatch(1);private final CountDownLatch waitLatch = new CountDownLatch(1);// 当前client等待的子节点private String waitPath;// 当前client创建的子节点private String currentMode;private String rootNode = "locks";private String subNode = "seq-";// 和 zk 服务建立连接,并创建根节点public DistributedLock() throws IOException, InterruptedException, KeeperException {// 获取连接zk = new ZooKeeper(CONNECTSTRING, SESSIONTIMEOUT, watchedEvent -> {// connectLatch 如果连接上zk 可以释放if (watchedEvent.getState() == Watcher.Event.KeeperState.SyncConnected) {connectLatch.countDown();}// waitLatch 需要释放if (watchedEvent.getType() == Watcher.Event.EventType.NodeDeleted && watchedEvent.getPath().equals(waitPath)) {waitLatch.countDown();}});// 等待zk正常连接后,往下走程序connectLatch.await();// 判断根节点/locks是否存在Stat stat = zk.exists("/" + rootNode, false);// 如果根节点不存在,则创建根节点,根节点类型为永久节点if (stat == null) {log.info("根节点不存在!!!");// 创建一下根节点zk.create("/" + rootNode, rootNode.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);}}// 对zk加锁public void zklock() {// 创建对应的临时带序号节点try {currentMode = zk.create("/" + rootNode + "/" + subNode, 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) {log.error("数据异常");} else if (index == 0) {// 就一个节点,可以获取锁了return;} else {// 需要监听 他前一个节点变化waitPath = "/locks/" + children.get(index - 1);zk.getData(waitPath, true, new Stat());// 等待监听waitLatch.await();return;}}} catch (InterruptedException | KeeperException e) {e.printStackTrace();Thread.currentThread().interrupt();}}// 解锁public void unZkLock() {// 删除节点try {zk.delete(this.currentMode, -1);} catch (KeeperException | InterruptedException e) {e.printStackTrace();Thread.currentThread().interrupt();}}}
分布式锁测试
(1)创建两个线程
package com.zhuang.zookeeper.case2;import lombok.extern.slf4j.Slf4j;
import org.apache.zookeeper.KeeperException;import java.io.IOException;@Slf4j
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(() -> {try {lock1.zklock();log.info("线程1 启动,获取到锁");Thread.sleep(5000);lock1.unZkLock();log.info("线程1 释放锁");} catch (InterruptedException e) {e.printStackTrace();Thread.currentThread().interrupt();}}).start();new Thread(() -> {try {lock2.zklock();log.info("线程2 启动,获取到锁");Thread.sleep(5000);lock2.unZkLock();log.info("线程2 释放锁");} catch (InterruptedException e) {e.printStackTrace();Thread.currentThread().interrupt();}}).start();}
}
(2) 观察控制台变化
线程1获取锁
线程1释放锁
线程2获取锁
线程2释放锁
Curator框架实现分布式锁案例
原生的 Java API开发存在的问题
(1) 会话连接是异步的,需要自己去处理。比如使用 CountDownLatch
(2) Watch需要重复注册,不然就不能生效
(3) 开发的复杂性还是比较高的
(4) 不支持多节点删除和创建。需要自己去递归
Curator是一个专门解决分布式锁的框架,解决了原生 Java API开发分布式遇到的问题。
详情请查看官方文档:
https://curator.apache.org/index.html
Curator案例实操
<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>
代码实现
package com.zhuang.zookeeper.case3;import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;@Slf4j
public class CuratorLockTest {public static void main(String[] args) {// 创建分布式锁1InterProcessMutex lock1 = new InterProcessMutex(getCuratorFramework(), "/locks");// 创建分布式锁2InterProcessMutex lock2 = new InterProcessMutex(getCuratorFramework(), "/locks");new Thread(() -> {try {lock1.acquire();log.info("线程1 获取到锁");lock1.acquire();log.info("线程1 再次获取到锁");Thread.sleep(5000);lock1.release();log.info("线程1 释放锁");lock1.release();log.info("线程1 再次释放锁");} catch (Exception e) {e.printStackTrace();Thread.currentThread().interrupt();}}).start();new Thread(() -> {try {lock2.acquire();log.info("线程2 获取到锁");lock2.acquire();log.info("线程2 再次获取到锁");Thread.sleep(5000);lock2.release();log.info("线程2 释放锁");lock2.release();log.info("线程2 再次释放锁");} catch (Exception e) {e.printStackTrace();Thread.currentThread().interrupt();}}).start();}private static CuratorFramework getCuratorFramework() {ExponentialBackoffRetry policy = new ExponentialBackoffRetry(3000, 3);CuratorFramework client = CuratorFrameworkFactory.builder().connectString("127.0.0.1:2181").connectionTimeoutMs(2000).sessionTimeoutMs(2000).retryPolicy(policy).build();// 启动客户端client.start();log.info("zookeeper 启动成功");return client;}
}
线程1获取锁
线程1再次获取锁
线程1释放锁
线程1再次释放锁
线程2获取锁
线程2再次获取锁
线程2释放锁
线程2再次释放锁
企业面试真题(面试重点)
选举机制
半数 机制 ,超过半数的投票通过,即通过。
(1)第一次启动选举规则
投票过半数时,
服务器 id大的胜出
(2)第二次启动选举规则
①EPOCH大的直接胜出
②EPOCH相同,事务 id大的胜出
③事务id相同,服务器 id大的胜出
生产集群安装多少zk合适
安装奇数台
生产经验:
- 10台 服务器: 3台 zk
- 20台 服务器: 5台 zk
- 100台 服务器: 11台 zk
- 200台 服务器: 11台 zk
服务器台数多:好处,提高可靠性;坏处:提高通信延时
常用命令
ls、 get、 create、 delete
SpringBoot整合Zookeeper
采用的版本apache-zookeeper-3.8.0-bin
创建SpringBoot项目导入依赖
<properties><java.version>8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.6.3</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--Curator--><dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>5.2.1</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>5.2.1</version></dependency><!--解决Spring Boot Configuration Annotation Processor not configured提示问题--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build>
配置application.yml
curator:#重试retryCount次,当会话超时出现后,curator会每间隔elapsedTimeMs毫秒时间重试一次,共重试retryCount次。retryCount: 5elapsedTimeMs: 5000#服务器信息connectString: 127.0.0.1:2181#会话超时时间设置sessionTimeoutMs: 60000#连接超时时间connectionTimeoutMs: 5000server:port: 80
Zookeeper配置类
package com.zhuang.zookeeper.config;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;/*** description: ZkConfig* date: 2023/4/9 22:06* author: Zhuang* version: 1.0*/
@Data
@Component
@ConfigurationProperties(prefix = "curator")
public class ZkConfig {private int retryCount;private int elapsedTimeMs;private String connectString;private int sessionTimeoutMs;private int connectionTimeoutMs;}
CuratorConfig
package com.zhuang.zookeeper.config;import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.RetryNTimes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** description: CuratorConfig* date: 2023/4/9 22:07* author: Zhuang* version: 1.0*/
@Configuration
public class CuratorConfig {@Autowiredprivate ZkConfig zkConfig;/*** 这里的start就是创建完对象放到容器后,需要调用他的start方法** @return CuratorFramework*/@Bean(initMethod = "start")public CuratorFramework curatorFramework() {return CuratorFrameworkFactory.newClient(zkConfig.getConnectString(),zkConfig.getSessionTimeoutMs(),zkConfig.getConnectionTimeoutMs(),new RetryNTimes(zkConfig.getRetryCount(), zkConfig.getElapsedTimeMs()));}}
创建Controller通过Postman测试
@RestController
@Slf4j
public class ZookeeperController {@Autowiredprivate CuratorFramework curatorFramework;}
创建节点
/*** 创建节点*/@PostMapping("/create/{nodeId}/{data}")public String createNode(@PathVariable String nodeId, @PathVariable String data) throws Exception {// 添加持久节点String path = curatorFramework.create().forPath("/" + nodeId);log.info("{} node :{} successfully!!!", nodeId, path);// 添加临时序号节点,并赋值数据curatorFramework.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/" + nodeId, data.getBytes());log.info("{} node :{} successfully!!!", nodeId, path);byte[] bytes = curatorFramework.getData().forPath("/" + nodeId);log.info(new String(bytes, StandardCharsets.UTF_8));return "create" + nodeId + "successfully!";}
获取指定节点的值
/*** 获取指定节点的值*/@GetMapping("/getNode/{nodeId}")public String getNode(@PathVariable String nodeId) throws Exception {byte[] bytes = curatorFramework.getData().forPath("/" + nodeId);log.info(new String(bytes, StandardCharsets.UTF_8));return new String(bytes, StandardCharsets.UTF_8);}
获取所有节点
/*** 获取所有节点*/@GetMapping("/getAllNode")public List<String> getAllData() throws Exception {return curatorFramework.getChildren().forPath("/");}
修改节点数据
/*** 修改节点数据*/@PutMapping("/updateData/{nodeId}/{newData}")public String testSetData(@PathVariable String nodeId, @PathVariable String newData) throws Exception {byte[] b1 = curatorFramework.getData().forPath("/" + nodeId);// 两个方法都可以实现修改节点数据,如果存在节点就修改值,不存在就创建curatorFramework.create().orSetData().forPath("/" + nodeId, newData.getBytes());//curatorFramework.setData().forPath("/curator-node", "康小庄!".getBytes());byte[] b2 = curatorFramework.getData().forPath("/" + nodeId);return "修改前" + nodeId + "节点的值" + new String(b1, StandardCharsets.UTF_8) + ",修改为->" + new String(b2, StandardCharsets.UTF_8);}
创建节点同时创建父节点
/*** 创建节点同时创建父节点*/@PostMapping("/createNode/{parentNodeId}/{childNodeId}")public String createWithParent(@PathVariable String parentNodeId, @PathVariable String childNodeId) throws Exception {String pathWithParent = "/" + parentNodeId + "/" + childNodeId;String path = curatorFramework.create().creatingParentsIfNeeded().forPath(pathWithParent);return "create node " + path + " successfully!!!";}
删除节点(包括子节点)
/*** 删除节点(包含子节点)*/@DeleteMapping("/deleteNode/{nodeId}")public String deleteNode(@PathVariable String nodeId) throws Exception {String pathWithParent = "/" + nodeId;curatorFramework.delete().guaranteed().deletingChildrenIfNeeded().forPath(pathWithParent);return "delete " + nodeId + " successfully";}
相关文章:

Zookeeper学习笔记
Zookeeper入门 Zookeeper 是一个开源的分布式的,为分布式框架提供协调服务的Apache 项目。 Zookeeper工作机制 Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,…...

go语言切片做函数参数传递+append()函数扩容
go语言切片函数参数传递append()函数扩容 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 二叉树递归go代码: var ans [][]int func pathSum(root *TreeNode, targetSum int) ( [][…...

2023.04.16 学习周报
文章目录 摘要文献阅读1.题目2.摘要3.简介4.Dual-Stage Attention-Based RNN4.1 问题定义4.2 模型4.2.1 Encoder with input attention4.2.2 Decoder with temporal attention4.2.3 Training procedure 5.实验5.1 数据集5.2 参数设置和评价指标5.3 实验结果 6.结论 MDS降维算法…...

【面试】如何设计SaaS产品的数据权限?
文章目录 前言数据权限是什么?设计原则整体方案RBAC模型怎么控制数据权限?1. 数据范围权限控制2. 业务对象操作权限控制3. 业务对象字段权限控制 总结 前言 一套系统的权限可以分为两类,数据权限和功能权限,今天我们从以下几个点…...

ansible管理变量
ansible变量简介 变量用于存储值,便于重复使用,可以简化项目的创建和维护。 变量命令规则 ansible变量的名称必须以字母开头,平且只能包含字母、数字和下划线,不允许有其他特殊字符。 变量范围 全局范围:从命令行…...

一种轻量级日志采集解决方案
前言 目前各大公司生产部署很多都是采用的集群微服务的部署方式,如果让日志散落在各个主机上,查询起来会非常的困难,所以目前我了解到的都是采用的日志中心来统一收集管控日志,日志中心的实现方案大多基于ELK(即Elasticsearch、L…...

【源码】Spring Cloud Gateway 是在哪里匹配路由的?
我们知道,经过网关的业务请求会被路由到后端真实的业务服务上去,假如我们使用的是Spring Cloud Gateway,那么你知道Spring Cloud Gateway是在哪一步去匹配路由的吗? 源码之下无秘密,让我们一起从源码中寻找答案。 入…...

BAT批处理基本命令
什么是 BAT 批处理脚本语言? BAT 批处理脚本语言是 Windows 系统自带的一种脚本语言,主要用于批量处理文件、目录、注册表、系统设置等任务。使用 BAT 批处理脚本语言可以节省大量手动操作的时间和精力。 如何编写 BAT 批处理脚本? 使用记事本…...

Python数组仿射变换
文章目录 仿射变换坐标变换的逻辑scipy实现 仿射变换 前面提到的平移、旋转以及缩放,都可以通过一个变换矩阵来实现,以二维空间中的变换矩阵为例,记点的坐标向量为 ( x , y , 1 ) (x,y,1) (x,y,1),则平移矩阵可表示为 [ 1 0 T x …...

“==“和equals方法究竟有什么区别?
操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用操作符。 如果一个变量指向的数据是对象类型的,那么,这时候…...

蓝桥杯15单片机--超声波模块
目录 一、超声波工作原理 二、超声波电路图 三、程序设计 1-设计思路 2-具体实现 四、程序源码 一、超声波工作原理 超声波时间差测距原理超声波发射器向某一方向发射超声波,在发射时刻的同时开始计时,超声波在空气中传播,途中碰到障碍…...

【学习笔记】ARC159
D - LIS 2 因为没有让你求方案数,所以还是比较好做的。 如果每一个连续段都退化成一个点,那么答案就是直接求 L I S LIS LIS。 否则,假设我们选了一些连续段把它们拼起来形成答案,显然我们有 r i 1 ≥ l i r_{i1}\ge l_i ri1…...

2023/4/16总结
图的存储 链式前向星 链式前向星和邻接表很相似,只是存储方式变成了数组。 链式前向星一般要用到一个结构体数组和一个一维数组,结构体数组edges中包括三个变量。结构体数组的大小一般由边的大小决定。 edges数组中的to代表的是某条边的终点v。w代表的是这条边的…...

【剑指offer】常用的数据增强的方法
系列文章目录 BN层详解 梯度消失和梯度爆炸 交叉熵损失函数 反向传播 1*1卷积的作用 文章目录 系列文章目录常用的数据增强的方法示例代码 常用的数据增强的方法 数据增强是指通过对原始数据进行一系列变换来生成更多的训练数据,从而提高模型的泛化能力。常用的数…...

/lib/lsb/init-functions文件解析
零、背景 在玩AppArmor的时候涉及到了/etc/init.d/apparmor(无论是sudo /etc/init.d/apparmor start还是sudo systemctl start apparmor.service),而这个文件又涉及到了另一个文件、也就是本文的主角:/lib/lsb/init-functions。 …...

【ChatGPT】ChatGPT-5 强到什么地步?
Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员,2024届电子信息研究生 目录 ChatGPT-5 强到什么地步? 技术 深度学习模型的升级 更好的预测能力 自适应学习能力 特点 语言理解能力更强 自我修正和优化 更广泛的应用领域 应用 对话系统 智能写作…...

[ARM+Linux] 基于全志h616外设开发笔记
修改用户密码 配置网络 nmcli dev wifi 命令扫描周围WIFI热点 nmcli dev wifi connect xxx password xxx 命令连接WiFi 查看ip地址的指令: ifconfig ip addr show wlan0 SSH登录 这是企业开发调试必用方式,比串口来说不用接线,前提是接入网络…...

如何实现24小时客户服务
许多企业都有着这样的愿望:在不增加客服人员的同时能实现24小时客户服务。 那么有没有什么方法可以实现这一想法呢?在想解决方案之前我们可以先来谈谈客服的作用。 客服的作用主要为以下2点: 帮助用户更快地了解产品(减轻产品的…...

查询数据库空间(mysql和oracle)
Mysql版 1、查看所有数据库容量大小 -- 查看所有数据库容量大小 SELECTtable_schema AS 数据库,sum( table_rows ) AS 记录数,sum(TRUNCATE ( data_length / 1024 / 1024, 2 )) AS 数据容量(MB),sum(TRUNCATE ( index_length / 1024 / 1024, 2 )) AS 索引容量(MB) FROMinfor…...

为什么 SQLite 一定要用 C 语言来开发?
SQLite 是一种专门为在 Unix 和类 Unix 操作系统上运行的 Linux 服务器应用程序而设计的数据库管理系统,是一种轻量级的关系型数据库管理系统,它适用于许多嵌入式设备和物联网设备。它使用 C 语言编写,并且是一个开源项目。 简单易用&#x…...

TensorFlow Lite,ML Kit 和 Flutter 移动深度学习:6~11
原文:Mobile Deep Learning with TensorFlow Lite, ML Kit and Flutter 协议:CC BY-NC-SA 4.0 译者:飞龙 本文来自【ApacheCN 深度学习 译文集】,采用译后编辑(MTPE)流程来尽可能提升效率。 不要担心自己的…...

你的GPT跟ChatGPT可能只差了一个DPU
“人类永远不会嫌网络太快,就像永远不会嫌高铁太快,你只会嫌它慢,希望它更快些。” 一个月内,百度、阿里、腾讯、商汤、讯飞、360等国内大厂扎堆发布“中国版 GPT ”,这家的名字还没记清楚,另一家的又蹦了出…...

springboot服务端接口外网远程调试,并实现HTTP服务监听 - 内网穿透
文章目录 前言1. 本地环境搭建1.1 环境参数1.2 搭建springboot服务项目 2. 内网穿透2.1 安装配置cpolar内网穿透2.1.1 windows系统2.1.2 linux系统 2.2 创建隧道映射本地端口2.3 测试公网地址 3. 固定公网地址3.1 保留一个二级子域名3.2 配置二级子域名3.2 测试使用固定公网地址…...

NumPy的应用-1
准备工作 在Python中使用NumPy时,需要先安装NumPy。可以使用以下命令来安装NumPy: pip install numpy安装完成后,在Python中引入NumPy: import numpy as np安装完成并引入NumPy后,我们可以开始使用NumPy进行数据分析…...

k8s的yaml文件中kind类型详解
在Kubernetes(k8s)的YAML语法中,kind是一种重要的关键字,它用于指定Kubernetes资源的类型。根据Kubernetes官方文档,以下是kind可能的取值: Deployment:用于定义应用程序的声明式更新。Statefu…...

第三天:C语言控制结构
目录 1. 条件语句 2. 循环语句 3. 实例:计算阶乘 在前两天的学习中,您已经掌握了C语言的基本知识。今天,我们将学习C语言的控制结构,包括条件语句和循环语句。通过控制结构,您可以实现程序的分支和循环,…...

访问若依vue版后端api接口
访问若依vue版后端api接口 如何使用Talend API Tester进行访问若依vue-前后端分离版的后端api接口? 方法一: 写好一个后台api接口,启动项目 直接使用Talend API Tester进行访问后台api出现如下错误,原因是因为若依系统有jwt认证…...

另一种迁移xxl-job任务的方法,适合不满足数据迁移条件
以为多个项目组同时使用一个xxl-job,同时涉及到版本提升,由此不太满足数据库数据迁移,所以这里提供另一种解决办法 使用工具:postman,json转excel,excel 核心:excel拼接: 1.使用f12抓取xxl任务访…...

Redis缓存穿透、击穿、雪崩面试题详解
缓存穿透 问题: 指的是客户端请求的数据在缓存中找不到,数据库中也没有存储,客户端还不断的发起请求。这样每次都无法在数据库查询到,缓存中永远没有这个数据。 这样的话,客户端一直去访问,会给后端数据…...

【网络安全】本地提权漏洞分析
0. 前言 CVE-2023-21752 是 2023 年开年微软第一个有 exploit 的漏洞,原本以为有利用代码会很好分析,但是结果花费了很长时间,难点主要了两个:漏洞点定位和漏洞利用代码分析,欢迎指正。 1. 漏洞简介 根据官方信息&a…...