SpringBoot基于Zookeeper和Curator生成唯一ID

目录

    • 一、简介
    • 二、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,数据视图都是一致的

二、maven依赖

  我这里把里面的日志框架都过滤了,加入了lombok,你们可以根据自己的需要进行相应的处理。
pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.5.2version>
        <relativePath/>
    parent>
    <groupId>com.aliangroupId>
    <artifactId>zookeeper-idartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>zookeeper-idname>
    <description>Spring Boot之zookeeper唯一iddescription>

    <properties>
        <java.version>1.8java.version>
    properties>
    <dependencies>

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
            <version>${parent.version}version>
        dependency>

        <dependency>
            <groupId>org.apache.zookeepergroupId>
            <artifactId>zookeeperartifactId>
            <version>3.6.3version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4jgroupId>
                    <artifactId>slf4j-log4j12artifactId>
                exclusion>
                <exclusion>
                    <groupId>org.slf4jgroupId>
                    <artifactId>slf4j-apiartifactId>
                exclusion>
                <exclusion>
                    <groupId>log4jgroupId>
                    <artifactId>log4jartifactId>
                exclusion>
            exclusions>
        dependency>

        <dependency>
            <groupId>org.apache.curatorgroupId>
            <artifactId>curator-frameworkartifactId>
            <version>5.2.0version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeepergroupId>
                    <artifactId>zookeeperartifactId>
                exclusion>
                <exclusion>
                    <groupId>org.slf4jgroupId>
                    <artifactId>slf4j-apiartifactId>
                exclusion>
            exclusions>
        dependency>

        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <version>1.16.14version>
        dependency>
    dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>

project>

三、配置

3.1、属性配置文件

  我们在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=5000

3.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 {
     

    /**
     * zookeeper服务地址
     */
    private String server;

    /**
     * 根路径
     */
    private String rootPath;

    /**
     * 重试等待时间
     */
    private int sleepTime;

    /**
     * 最大重试次数
     */
    private int maxRetries;

    /**
     * session超时时间
     */
    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());
        }
    }

    /**
     * 分布式ID生成
     */
    public String generateId(String nodeName) {
     
        //创建临时自动编号的顺序节点,返回的是一个路径
        String nodeFullPath = createSeqNode(nodeName);
        if (null == nodeFullPath) {
     
            return "";
        }
        String generateId = splitSeqNode(nodeFullPath);
        log.info("节点编号:" + generateId);
        return generateId;
    }

    /**
     * 创建顺序节点,约定nodePrefix不能为空,也不能用"/"开头或结尾
     */
    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;

    /**
     * 生成id
     *
     * @return
     */
    @RequestMapping("/generateId")
    public String generateId(HttpServletRequest request) {
     
    	//我们这里传入前缀为时间字符串:yyyyMMddHHmmssSSS
        String nodeName = LocalDateTime.now().format(formatter);
        return zookeeperClient.generateId(nodeName);
    }
}

五、测试

5.1、多实例

  由于我们是windows环境下的本机开发及测试,我们使用idea启动两个实例进行负载均衡,端口分别为80888090。如果不懂的可以参考我另一篇文章:windows下Nginx配置及负载均衡使用

application.yml

server:
  port: 8088
  servlet:
    context-path: /zookeeperId

两个实例启动的示例图:
SpringBoot基于Zookeeper和Curator生成唯一ID_第1张图片

5.2、nginx转发配置

  自定义配置文件localhost_80.confserver模块里增加转发配置,通过负载均衡到两个实例上。

	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表示请求循环的次数。
SpringBoot基于Zookeeper和Curator生成唯一ID_第2张图片
我们请求的地址是:http://localhost/zookeeperId/distributed/generateId,注意是没有端口的,会通过nginx转发到后台实例。

SpringBoot基于Zookeeper和Curator生成唯一ID_第3张图片

5.4、测试结果

端口为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.3curator-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版本也要改成,你可以多尝试几次,我一般喜欢使用新的版本。

你可能感兴趣的:(Spring,Boot,spring,boot,zookeeper,分布式)