- 一、简介
- 二、maven依赖
- 三、配置
- 3.1、属性配置文件
- 3.2、属性配置类
- 3.3、zookeeper配置类(核心)
- 四、具体使用
- 4.1、zookeeperClient(核心)
- 4.2、controller层
- 五、测试
- 5.1、多实例
- 5.2、nginx转发配置
- 5.3、使用jmeter并发测试
- 5.4、测试结果
zookeeper是一个分布式的,开放源码的分布式应用程序协调服务,它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。选择zookeeper的原因,因为zookeeper具有以下优点:
- 可靠性:如果消息被到一台服务器接受,那么它将被所有的服务器接受。
- 实时性:在一定事件范围内,client能读到最新数据,如果需要最新数据,应该在读数据之前调用sync()接口
- 独立性:各个Client之间互不干预
- 顺序性:更新请求顺序进行,来自同一个client的更新请求按其发送顺序依次执行
- 原子性:一次数据的更新只能成功或者失败,没有其他中间状态
- 最终一致性:全局唯一数据视图,client无论连接到哪个server,数据视图都是一致的
我这里把里面的日志框架都过滤了,加入了lombok,你们可以根据自己的需要进行相应的处理。
pom.xml
三、配置 3.1、属性配置文件4.0.0 org.springframework.boot spring-boot-starter-parent 2.5.2 com.alian zookeeper-id 0.0.1-SNAPSHOT zookeeper-id Spring Boot之zookeeper唯一id 1.8 org.springframework.boot spring-boot-starter-web ${parent.version} org.apache.zookeeper zookeeper 3.6.3 org.slf4j slf4j-log4j12 org.slf4j slf4j-api log4j log4j org.apache.curator curator-framework 5.2.0 org.apache.zookeeper zookeeper org.slf4j slf4j-api org.projectlombok lombok 1.16.14 org.springframework.boot spring-boot-maven-plugin
我们在resource目录下建一个config文件夹,然后在resource/config目录下创建zookeeper的自定义配置文件zookeeper.properties,主要是zookeeper连接和目录相关的配置,因为本机的配置原因,我这里就没有采用zookeeper的集群模式了,Zookeeper建议集群节点个数为奇数(大于等于3),只要超过一半的机器能够正常提供服务,那么整个集群都是可用的状态。
zookeeper.properties
# zookeeper服务器地址(ip+port) zookeeper.server=10.130.3.16:2181 # 节点创建的路径约定用"/"结尾 zookeeper.rootPath=/root/alian/ # 休眠时间 zookeeper.sleep-time=1000 # 最大重试次数 zookeeper.max-retries=3 # 会话超时时间 zookeeper.session-timeout=5000 # 连接超时时间 zookeeper.connection-timeout=50003.2、属性配置类
此配置类不懂的可以参考我另一篇文章:Spring Boot读取配置文件常用方式
ZookeeperProperties.java
package com.alian.zookeeperid.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "zookeeper")
//读取指定路径配置文件,暂不支持*.yaml文件
@PropertySource(value = "classpath:config/zookeeper.properties", encoding = "UTF-8", ignoreResourceNotFound = true)
public class ZookeeperProperties {
private String server;
private String rootPath;
private int sleepTime;
private int maxRetries;
private int sessionTimeout;
private int connectionTimeout;
}
3.3、zookeeper配置类(核心)
为什么要使用Curator,因为Curator提供了简化使用zookeeper更高级的API接口,Curatorframework实例都是线程安全的。它包涵很多优秀的特性:
- 自动连接管理:自动处理zookeeper的连接和重试存在一些潜在的问题,可以监控节点数据改变和获取更新服务的列表,而监控又可以自动被Cruator recipes删除
- 更简洁的API:提供现代流式API接口,简化了原生zookeeper方法,事件等
- Recipe实现:可以应用到leader选举,分布式锁,path缓存,和watcher,分布式队列等
ZookeeperConfig.java
package com.alian.zookeeperid.config;
import com.alian.zookeeperid.common.ZookeeperClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.Curatorframework;
import org.apache.curator.framework.CuratorframeworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Slf4j
@Configuration
public class ZookeeperConfig {
@Autowired
private ZookeeperProperties zookeeperProperties;
@Bean
public Curatorframework curatorframeworkClient() {
//重试策略,ExponentialBackoffRetry(1000,3)这里表示等待1s重试,最大重试次数为3次
RetryPolicy policy = new ExponentialBackoffRetry(zookeeperProperties.getSleepTime(), zookeeperProperties.getMaxRetries());
//构建Curatorframework实例
Curatorframework curatorframeworkClient = CuratorframeworkFactory
.builder()
.connectString(zookeeperProperties.getServer())
.sessionTimeoutMs(zookeeperProperties.getSessionTimeout())
.connectionTimeoutMs(zookeeperProperties.getConnectionTimeout())
.retryPolicy(policy)
.build();
//启动实例
curatorframeworkClient.start();
return curatorframeworkClient;
}
//采用这种方式可以比较优雅的关闭连接
@Bean(initMethod = "init", destroyMethod = "destroy")
public ZookeeperClient zookeeperClient(ZookeeperProperties zookeeperProperties, Curatorframework curatorframeworkClient) {
return new ZookeeperClient(zookeeperProperties, curatorframeworkClient);
}
}
四、具体使用
4.1、zookeeperClient(核心)
此组件主要是完成,顺序节点的创建,我这里创建的是临时顺利节点,如果担心节点过多可以采用异步线程删除节点,我这里也只是一个示例。我想我代码的注释比这个惨白的文字要更有说服力。很多小伙伴可能会采用@Component注解,我使用@Bean(initMethod = “init”, destroyMethod = “destroy”)来创建,可以比较优雅的关闭连接,当然在使用上是一样的,只要不是同时对一个bean这么操作。
zookeeperClient.java
package com.alian.zookeeperid.common;
import com.alian.zookeeperid.config.ZookeeperProperties;
import com.sun.istack.internal.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.Curatorframework;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Slf4j
public class ZookeeperClient {
private ZookeeperProperties zookeeperProperties;
private static ExecutorService executorService;
private Curatorframework curatorframework;
public Curatorframework getCuratorframework() {
return curatorframework;
}
public ZookeeperClient(ZookeeperProperties zookeeperProperties, Curatorframework curatorframework) {
this.zookeeperProperties = zookeeperProperties;
this.curatorframework = curatorframework;
}
public void init() {
log.info("ZookeeperClient初始化方法,新建线程池,用于删除临时节点");
try {
//线程池用于删除异步删除节点
executorService = Executors.newFixedThreadPool(10);
} catch (Exception e) {
log.error("ZookeeperClient init error {}", e.getMessage());
}
}
public void destroy() {
try {
log.info("ZookeeperClient销毁方法,如果zookeeper连接不为空,则关闭连接");
if (getCuratorframework() != null) {
//这种方式比较优雅的关闭连接
getCuratorframework().close();
}
} catch (Exception e) {
log.error("stop zookeeper client error {}", e.getMessage());
}
}
public String generateId(String nodeName) {
//创建临时自动编号的顺序节点,返回的是一个路径
String nodeFullPath = createSeqNode(nodeName);
if (null == nodeFullPath) {
return "";
}
String generateId = splitSeqNode(nodeFullPath);
log.info("节点编号:" + generateId);
return generateId;
}
private String createSeqNode(@NotNull String nodePrefix) {
if ("".equals(nodePrefix.trim()) || nodePrefix.startsWith("/") || nodePrefix.endsWith("/")) {
log.error("节点前缀错误");
return "";
}
String nodeFullPath = "";
//根路径+要创建节点的名称(可以是路径,此处传入的nodeName不要用"/"开头或结尾)
String fullPath = zookeeperProperties.getRootPath().concat(nodePrefix);
try {
//关键点:创建临时顺序节点
//creatingParentsIfNeeded():如果传入的是路径,并且节点父路径不存在则创建父节点
nodeFullPath = curatorframework
.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
.forPath(fullPath);
//为防止生成的节点浪费系统资源,故生成后异步删除此节点
cleanNode(nodeFullPath);
} catch (Exception e) {
log.error("创建临时顺序节点异常{}", e.getMessage());
e.printStackTrace();
}
return nodeFullPath;
}
private void cleanNode(String finalBackNodePath) {
executorService.execute(() -> {
try {
//Thread.sleep(10);
Stat stat = curatorframework.checkExists().forPath(finalBackNodePath);
if (stat != null) {
// log.info("------------" + new String(curatorframework.getData().forPath("/zookeeper/alian")));
curatorframework.delete().forPath(finalBackNodePath);
// log.info("删除的临时节点:{}", finalBackNodePath);
}
} catch (Exception e) {
log.error("删除节点异常{}", e.getMessage());
e.printStackTrace();
}
});
}
private String splitSeqNode(String path) {
//获取最后一个"/"的索引,用于字符串截取
int index = path.lastIndexOf("/");
if (index >= 0) {
//如果"/"位置比路径长度小,则截取"/"后面的作为节点返回
//如果"/"位置等于路径长度,说明它后面没有元素,返回空字符串
return index <= path.length() ? path.substring(index + 1) : "";
}
//不含"/",说明是节点数据,直接返回(理论上不会,因为都是"/"开头的路径,至少有一个"/")
return path;
}
}
关于zookeeper里节点的模式,新版又增加了两个带TTL的持久化节点,节点模式:
- PERSISTENT:持久化节点
- PERSISTENT_SEQUENTIAL:持久化的顺序自动编号节点
- EPHEMERAL:临时节点
- EPHEMERAL_SEQUENTIAL:临时顺序自动编号节点
- CONTAINER:容器节点
- PERSISTENT_WITH_TTL:带TTL(time-to-live,存活时间)的持久化节点,节点在TTL时间之内没有得到更新并且没有子节点,就会被自动删除
- PERSISTENT_SEQUENTIAL_WITH_TTL:带TTL(time-to-live,存活时间)和单调递增序号的持久节点,节点在TTL时间之内没有得到更新并且没有子节点,就会被自动删除
可能很多小伙伴不知道怎么创建待TTL的节点,我也给大家准备了,主要是使用withTtl(5000L)设置过期
String fullPath="/root/alian/";
String nodePath = curatorframework
.create()
.withTtl(5000L)
.creatingParentsIfNeeded()
.withMode(CreateMode.PERSISTENT_SEQUENTIAL_WITH_TTL)
.forPath(fullPath);
4.2、controller层
简单的一个获取id的接口,仅仅是为了演示,实际中肯定更加严格和规范。生成时间字符串yyyyMMddHHmmssSSS+zookeeper生产的id,组成我们需要的id,当然你也可以使用其他的前缀。
DistributedIdController.java
package com.alian.zookeeperid.controller;
import com.alian.zookeeperid.common.ZookeeperClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Slf4j
@RestController
@RequestMapping("/distributed")
public class DistributedIdController {
private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
@Autowired
private ZookeeperClient zookeeperClient;
@RequestMapping("/generateId")
public String generateId(HttpServletRequest request) {
//我们这里传入前缀为时间字符串:yyyyMMddHHmmssSSS
String nodeName = LocalDateTime.now().format(formatter);
return zookeeperClient.generateId(nodeName);
}
}
五、测试
5.1、多实例
由于我们是windows环境下的本机开发及测试,我们使用idea启动两个实例进行负载均衡,端口分别为8088和8090。如果不懂的可以参考我另一篇文章:windows下Nginx配置及负载均衡使用
application.yml
server:
port: 8088
servlet:
context-path: /zookeeperId
两个实例启动的示例图:
自定义配置文件localhost_80.conf里server模块里增加转发配置,通过负载均衡到两个实例上。
location ~ ^/zookeeperId/ {
proxy_redirect off;
#端口
proxy_set_header Host $host;
#远程地址
proxy_set_header X-Real-IP $remote_addr;
#程序可获取远程ip地址
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#此处会用的upstream.conf,此文件在nginx.conf已经引入了
proxy_pass http://zookeeper-id;
}
负载均衡配置upstream.conf文件增加下面的配置,其中zookeeper-id 就是localhost_80.conf文件里配置的http://zookeeper-id;
upstream zookeeper-id {
server 127.0.0.1:8088 ;
server 127.0.0.1:8090 ;
}
如果你的nginx已经启动,最后记得使用命令nginx -t 检查和nginx -s reload应用。
5.3、使用jmeter并发测试 本文中使用使用100个线程请求我的接口获取id,100表示线程数,0表示0秒内一起发送,1表示请求循环的次数。
我们请求的地址是:http://localhost/zookeeperId/distributed/generateId,注意是没有端口的,会通过nginx转发到后台实例。
端口为8088实例的结果:
2021-10-20 15:25:51 347 [http-nio-8088-exec-21] INFO generateId 39:节点编号:202110201525512590000000001 2021-10-20 15:25:51 347 [http-nio-8088-exec-7] INFO generateId 39:节点编号:202110201525512600000000003 2021-10-20 15:25:51 347 [http-nio-8088-exec-31] INFO generateId 39:节点编号:202110201525512590000000005 2021-10-20 15:25:51 348 [http-nio-8088-exec-23] INFO generateId 39:节点编号:202110201525512590000000007 2021-10-20 15:25:51 349 [http-nio-8088-exec-30] INFO generateId 39:节点编号:202110201525512600000000009 2021-10-20 15:25:51 350 [http-nio-8088-exec-10] INFO generateId 39:节点编号:202110201525512600000000012 2021-10-20 15:25:51 350 [http-nio-8088-exec-14] INFO generateId 39:节点编号:202110201525512590000000014 2021-10-20 15:25:51 351 [http-nio-8088-exec-29] INFO generateId 39:节点编号:202110201525512590000000017 2021-10-20 15:25:51 352 [http-nio-8088-exec-5] INFO generateId 39:节点编号:202110201525512600000000019 2021-10-20 15:25:51 352 [http-nio-8088-exec-8] INFO generateId 39:节点编号:202110201525512600000000022 2021-10-20 15:25:51 352 [http-nio-8088-exec-38] INFO generateId 39:节点编号:202110201525512590000000020 2021-10-20 15:25:51 353 [http-nio-8088-exec-15] INFO generateId 39:节点编号:202110201525512590000000028 2021-10-20 15:25:51 353 [http-nio-8088-exec-48] INFO generateId 39:节点编号:202110201525512600000000024 2021-10-20 15:25:51 354 [http-nio-8088-exec-35] INFO generateId 39:节点编号:202110201525512590000000027 2021-10-20 15:25:51 354 [http-nio-8088-exec-18] INFO generateId 39:节点编号:202110201525512600000000029 2021-10-20 15:25:51 354 [http-nio-8088-exec-26] INFO generateId 39:节点编号:202110201525512590000000032 2021-10-20 15:25:51 355 [http-nio-8088-exec-45] INFO generateId 39:节点编号:202110201525512600000000035 2021-10-20 15:25:51 355 [http-nio-8088-exec-22] INFO generateId 39:节点编号:202110201525512590000000036 2021-10-20 15:25:51 356 [http-nio-8088-exec-12] INFO generateId 39:节点编号:202110201525512590000000038 2021-10-20 15:25:51 356 [http-nio-8088-exec-41] INFO generateId 39:节点编号:202110201525512600000000040 2021-10-20 15:25:51 357 [http-nio-8088-exec-49] INFO generateId 39:节点编号:202110201525512590000000043 2021-10-20 15:25:51 357 [http-nio-8088-exec-50] INFO generateId 39:节点编号:202110201525512600000000044 2021-10-20 15:25:51 358 [http-nio-8088-exec-34] INFO generateId 39:节点编号:202110201525512600000000046 2021-10-20 15:25:51 358 [http-nio-8088-exec-11] INFO generateId 39:节点编号:202110201525512590000000048 2021-10-20 15:25:51 359 [http-nio-8088-exec-42] INFO generateId 39:节点编号:202110201525512600000000052 2021-10-20 15:25:51 359 [http-nio-8088-exec-9] INFO generateId 39:节点编号:202110201525512590000000050 2021-10-20 15:25:51 359 [http-nio-8088-exec-19] INFO generateId 39:节点编号:202110201525512590000000055 2021-10-20 15:25:51 360 [http-nio-8088-exec-17] INFO generateId 39:节点编号:202110201525512590000000057 2021-10-20 15:25:51 361 [http-nio-8088-exec-1] INFO generateId 39:节点编号:202110201525512600000000059 2021-10-20 15:25:51 361 [http-nio-8088-exec-25] INFO generateId 39:节点编号:202110201525512600000000061 2021-10-20 15:25:51 362 [http-nio-8088-exec-16] INFO generateId 39:节点编号:202110201525512600000000065 2021-10-20 15:25:51 362 [http-nio-8088-exec-43] INFO generateId 39:节点编号:202110201525512600000000067 2021-10-20 15:25:51 362 [http-nio-8088-exec-6] INFO generateId 39:节点编号:202110201525512600000000062 2021-10-20 15:25:51 364 [http-nio-8088-exec-39] INFO generateId 39:节点编号:202110201525512590000000069 2021-10-20 15:25:51 364 [http-nio-8088-exec-4] INFO generateId 39:节点编号:202110201525512600000000073 2021-10-20 15:25:51 366 [http-nio-8088-exec-40] INFO generateId 39:节点编号:202110201525512590000000075 2021-10-20 15:25:51 366 [http-nio-8088-exec-32] INFO generateId 39:节点编号:202110201525512600000000081 2021-10-20 15:25:51 366 [http-nio-8088-exec-33] INFO generateId 39:节点编号:202110201525512590000000079 2021-10-20 15:25:51 367 [http-nio-8088-exec-27] INFO generateId 39:节点编号:202110201525512600000000085 2021-10-20 15:25:51 367 [http-nio-8088-exec-46] INFO generateId 39:节点编号:202110201525512600000000087 2021-10-20 15:25:51 368 [http-nio-8088-exec-44] INFO generateId 39:节点编号:202110201525512600000000098 2021-10-20 15:25:51 367 [http-nio-8088-exec-47] INFO generateId 39:节点编号:202110201525512590000000089 2021-10-20 15:25:51 367 [http-nio-8088-exec-28] INFO generateId 39:节点编号:202110201525512590000000091 2021-10-20 15:25:51 367 [http-nio-8088-exec-20] INFO generateId 39:节点编号:202110201525512600000000097 2021-10-20 15:25:51 367 [http-nio-8088-exec-13] INFO generateId 39:节点编号:202110201525512600000000077 2021-10-20 15:25:51 368 [http-nio-8088-exec-2] INFO generateId 39:节点编号:202110201525512600000000099 2021-10-20 15:25:51 367 [http-nio-8088-exec-37] INFO generateId 39:节点编号:202110201525512590000000084 2021-10-20 15:25:51 367 [http-nio-8088-exec-36] INFO generateId 39:节点编号:202110201525512600000000092 2021-10-20 15:25:51 367 [http-nio-8088-exec-3] INFO generateId 39:节点编号:202110201525512590000000095 2021-10-20 15:25:51 367 [http-nio-8088-exec-24] INFO generateId 39:节点编号:202110201525512600000000071
端口为8090实例的结果:
2021-10-20 15:25:51 347 [http-nio-8090-exec-18] INFO generateId 39:节点编号:202110201525512570000000000 2021-10-20 15:25:51 347 [http-nio-8090-exec-30] INFO generateId 39:节点编号:202110201525512560000000002 2021-10-20 15:25:51 347 [http-nio-8090-exec-12] INFO generateId 39:节点编号:202110201525512550000000004 2021-10-20 15:25:51 349 [http-nio-8090-exec-34] INFO generateId 39:节点编号:202110201525512560000000010 2021-10-20 15:25:51 348 [http-nio-8090-exec-27] INFO generateId 39:节点编号:202110201525512560000000006 2021-10-20 15:25:51 349 [http-nio-8090-exec-24] INFO generateId 39:节点编号:202110201525512560000000008 2021-10-20 15:25:51 349 [http-nio-8090-exec-14] INFO generateId 39:节点编号:202110201525512560000000011 2021-10-20 15:25:51 349 [http-nio-8090-exec-40] INFO generateId 39:节点编号:202110201525512560000000013 2021-10-20 15:25:51 350 [http-nio-8090-exec-1] INFO generateId 39:节点编号:202110201525512560000000015 2021-10-20 15:25:51 350 [http-nio-8090-exec-13] INFO generateId 39:节点编号:202110201525512550000000016 2021-10-20 15:25:51 351 [http-nio-8090-exec-6] INFO generateId 39:节点编号:202110201525512560000000018 2021-10-20 15:25:51 352 [http-nio-8090-exec-39] INFO generateId 39:节点编号:202110201525512560000000021 2021-10-20 15:25:51 353 [http-nio-8090-exec-17] INFO generateId 39:节点编号:202110201525512560000000023 2021-10-20 15:25:51 353 [http-nio-8090-exec-5] INFO generateId 39:节点编号:202110201525512560000000025 2021-10-20 15:25:51 353 [http-nio-8090-exec-4] INFO generateId 39:节点编号:202110201525512550000000026 2021-10-20 15:25:51 354 [http-nio-8090-exec-11] INFO generateId 39:节点编号:202110201525512550000000031 2021-10-20 15:25:51 354 [http-nio-8090-exec-33] INFO generateId 39:节点编号:202110201525512560000000030 2021-10-20 15:25:51 354 [http-nio-8090-exec-23] INFO generateId 39:节点编号:202110201525512560000000033 2021-10-20 15:25:51 354 [http-nio-8090-exec-26] INFO generateId 39:节点编号:202110201525512560000000034 2021-10-20 15:25:51 355 [http-nio-8090-exec-49] INFO generateId 39:节点编号:202110201525512550000000037 2021-10-20 15:25:51 356 [http-nio-8090-exec-2] INFO generateId 39:节点编号:202110201525512560000000039 2021-10-20 15:25:51 356 [http-nio-8090-exec-35] INFO generateId 39:节点编号:202110201525512550000000041 2021-10-20 15:25:51 357 [http-nio-8090-exec-19] INFO generateId 39:节点编号:202110201525512560000000042 2021-10-20 15:25:51 357 [http-nio-8090-exec-50] INFO generateId 39:节点编号:202110201525512560000000045 2021-10-20 15:25:51 358 [http-nio-8090-exec-3] INFO generateId 39:节点编号:202110201525512560000000047 2021-10-20 15:25:51 359 [http-nio-8090-exec-43] INFO generateId 39:节点编号:202110201525512560000000049 2021-10-20 15:25:51 359 [http-nio-8090-exec-47] INFO generateId 39:节点编号:202110201525512560000000051 2021-10-20 15:25:51 359 [http-nio-8090-exec-25] INFO generateId 39:节点编号:202110201525512560000000053 2021-10-20 15:25:51 359 [http-nio-8090-exec-48] INFO generateId 39:节点编号:202110201525512560000000054 2021-10-20 15:25:51 360 [http-nio-8090-exec-10] INFO generateId 39:节点编号:202110201525512560000000056 2021-10-20 15:25:51 361 [http-nio-8090-exec-15] INFO generateId 39:节点编号:202110201525512560000000060 2021-10-20 15:25:51 361 [http-nio-8090-exec-9] INFO generateId 39:节点编号:202110201525512560000000058 2021-10-20 15:25:51 362 [http-nio-8090-exec-31] INFO generateId 39:节点编号:202110201525512560000000064 2021-10-20 15:25:51 363 [http-nio-8090-exec-29] INFO generateId 39:节点编号:202110201525512550000000063 2021-10-20 15:25:51 363 [http-nio-8090-exec-36] INFO generateId 39:节点编号:202110201525512560000000066 2021-10-20 15:25:51 364 [http-nio-8090-exec-37] INFO generateId 39:节点编号:202110201525512560000000070 2021-10-20 15:25:51 362 [http-nio-8090-exec-22] INFO generateId 39:节点编号:202110201525512560000000068 2021-10-20 15:25:51 364 [http-nio-8090-exec-20] INFO generateId 39:节点编号:202110201525512570000000072 2021-10-20 15:25:51 364 [http-nio-8090-exec-42] INFO generateId 39:节点编号:202110201525512560000000074 2021-10-20 15:25:51 364 [http-nio-8090-exec-28] INFO generateId 39:节点编号:202110201525512550000000076 2021-10-20 15:25:51 365 [http-nio-8090-exec-44] INFO generateId 39:节点编号:202110201525512570000000080 2021-10-20 15:25:51 365 [http-nio-8090-exec-32] INFO generateId 39:节点编号:202110201525512560000000083 2021-10-20 15:25:51 365 [http-nio-8090-exec-21] INFO generateId 39:节点编号:202110201525512560000000078 2021-10-20 15:25:51 365 [http-nio-8090-exec-46] INFO generateId 39:节点编号:202110201525512550000000082 2021-10-20 15:25:51 365 [http-nio-8090-exec-8] INFO generateId 39:节点编号:202110201525512560000000086 2021-10-20 15:25:51 366 [http-nio-8090-exec-45] INFO generateId 39:节点编号:202110201525512560000000088 2021-10-20 15:25:51 366 [http-nio-8090-exec-16] INFO generateId 39:节点编号:202110201525512560000000090 2021-10-20 15:25:51 367 [http-nio-8090-exec-38] INFO generateId 39:节点编号:202110201525512560000000093 2021-10-20 15:25:51 368 [http-nio-8090-exec-7] INFO generateId 39:节点编号:202110201525512560000000094 2021-10-20 15:25:51 368 [http-nio-8090-exec-41] INFO generateId 39:节点编号:202110201525512560000000096
从上述结果来看,每次生成的id确实是不一样的。生成的节点为10位从0000000000开始编号,每个线程打印的顺序可能会有先后,最后生成的节点还是从0000000000~0000000099,00000000099在8088端口实例里输出了,本例里是倒数第5个。
需要提醒的是本文中zookeeper服务的版本是3.6.3,curator-framework的版本是5.2.0,如果你的zookeeper服务版本是3.4.x,可能就会出现问题。
org.apache.zookeeper.ClientCnxn$SessionTimeoutException: Client session timed out, have not heard from server in 10106ms for session id 0x0
这时你就需要去更改你依赖里的版本为3.4.x,同时需要注意的是你的curator-framework版本也要改成,你可以多尝试几次,我一般喜欢使用新的版本。



