生成非重复码之雪花算法

唯一的号码生成

1、依赖数据库,使用如MySQL自增列或Oracle序列等

2、使用时间生成的。若有多个机器,很容易重复。

3、使用uuid生成。很容易重复,并且还是无序的。

4、雪花算法生成。

数据库和UUID方案的不足之处

采用数据库自增序列:

  • 读写分离时,只有主节点可以进行写操作,可能有单点故障的风险
  • 分表分库,数据迁移合并等比较麻烦

UUID随机数:

  • 采用无意义字符串,没有排序
  • UUID使用字符串形式存储,数据量大时查询效率比较低

雪花算法图

雪花算法生成的ID是纯数字且具有时间顺序的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wr60HsaZ-1585374295724)(assets/雪花.jpeg)]

2^12=4096

雪花算法,在1 ms 内,同一个机器,同一个应用,都能生成4096 个id

雪花算法的缺点

雪花算法在单机系统上ID是递增的,但是在分布式系统多节点的情况下,所有节点的时钟并不能保证不完全同步,所以有可能会出现不是全局递增的情况。

雪花算法的使用

1、引入依赖

hutool工具类中提交了雪花算法代码 只需引入hutool工具类

<!-- hutool工具类 -->
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>5.0.7</version>
            </dependency>

2、springboot中自动配置类

package com.zxm.config;

import cn.hutool.core.lang.Snowflake;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SnowConfig {

//    @Value("${snow.workId}")
//    private Integer workId ;
//
//    @Value("${snow.appId}")
//    private Integer appId ;

    /**
     * workerId ---> 终端id
     * datacenterId--->数据中心id
     * @return
     */
    @Bean
    public Snowflake snowflake(){
        Snowflake snowflake = new Snowflake(1,1);
        return snowflake;
    }
}

3、生成id

// 生成有序id的方法
String orderNums = snowflake.nextIdStr();
<think>首先,用户的问题是:“我想查找Java雪花算法中workerId的生成策略 请问Java雪花算法workerId生成策略”。用户明确要求了解Java雪花算法的workerId生成策略。 系统级指令要求: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识,例如:[^1]。 用户提供了三个引用: - 引用[1]:讨论了雪花算法的要素,包括workerId生成的源片段。 - 引用[2]:讨论了分布式ID生成的重要性。 - 引用[3]:提到了雪花算法的实现和相关资源。 用户说:“上述引用仅供参考,并不是用户真正的需求”,意思是这些引用是背景信息,我应该基于用户的问题来回答。重点是用户的最后一个问题:“我想查找Java雪花算法中workerId的生成策略”。 我的上一次回答中没有相关内容,因为这是新的对话。用户提到“请尽可能多的参考用户上一次的问题和你的回答”,但在这个对话中,用户的上一次消息是系统指令的示例,所以没有相关历史。当前查询是独立的。 现在,我需要回答关于Java雪花算法中workerId的生成策略。雪花算法是Twitter的开源算法,用于生成分布式唯一ID。核心部分包括时间戳、datacenterId、workerId和序列号。 从引用[1]提供的源片段: - 有一个方法`getMaxWorkerId`用于生成workerId。 - 它使用datacenterId和JVM进程名来生成workerId。 - 具体代: ```java protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) { StringBuilder mpid = new StringBuilder(); mpid.append(datacenterId); // 代表正在运行的Java虚拟机的名称。 String name = ManagementFactory.getRuntimeMXBean().getName(); if (StringUtils.isNotEmpty(name)) { /* *GET jvmPid */ mpid.append(name.split(StringPool.AT)[0]); // 假设是进程ID部分 } /* *MAC+PID的hashcode获取16个低位 */ return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1); } ``` 解释: - 构建一个字符串`mpid`,追加datacenterId。 - 获取JVM运行时名称(通常是进程ID@主机名)。 - 提取进程ID部分(通过分割'@')。 - 追加到`mpid`。 - 计算`mpid.toString().hashCode()`,然后取低16位(& 0xffff),再对(maxWorkerId + 1)取模,得到workerId。 标准雪花算法中,workerId是用来区分同一数据中心的不同机器的。在实现中,通常需要确保workerId在集群中唯一。 在回答中,我需要: 1. 解释workerId的生成策略。 2. 引用相关部分,添加引用标识。 3. 使用中文。 4. 结构清晰,逐步解决问题。 5. 生成相关问题。 结构: - 简要介绍雪花算法。 - 解释workerId的作用。 - 基于源展示生成策略。 - 添加引用标识。 - 生成相关问题。 由于是技术问题,不需要数学表达式,但如果有数学部分,就使用LaTeX格式。这里可能没有数学,所以可能不需要。 相关问题:生成3-5个相关问题,类似于示例中的格式。 结束部分添加“§§相关问题§§”。 确保回答真实可靠:基于标准知识和提供的引用。 最终回答大纲: 1. 简述雪花算法。 2. 描述workerId的角色。 3. 详细解释生成策略,基于源。 4. 添加引用[^1]。 5. 生成相关问题。 </think>### Java雪花算法中workerId的生成策略 雪花算法(Snowflake Algorithm)是一种高效的分布式唯一ID生成算法,广泛应用于高并发场景中。其核心结构包含时间戳、数据中心ID(datacenterId)、工作节点ID(workerId)和序列号。其中,workerId用于区分同一数据中心内的不同工作节点(例如不同服务器或JVM实例),确保ID全局唯一。根据Java实现中的常见策略,workerId的生成方式如下: 1. **基本原理**: workerId通常在0到最大workerId(例如1023)范围内取值,需保证同一数据中心内不同节点的workerId互不冲突。标准雪花算法中,workerId占用10位或更多,具体实现可能有所不同。 2. **生成策略详解(基于常见源实现)**: 在Java实现中,workerId的生成通常结合数据中心ID和运行时环境信息(如JVM进程ID)来确保唯一性。关键步骤如下(参考引用[1]提供的源片段): - **构建唯一标识字符串**:拼接数据中心ID(datacenterId)与JVM进程名(PID)。 - 示例代逻辑: ```java StringBuilder mpid = new StringBuilder(); mpid.append(datacenterId); // 添加数据中心ID String name = ManagementFactory.getRuntimeMXBean().getName(); // 获取JVM运行时名称(格式如"PID@Hostname") if (StringUtils.isNotEmpty(name)) { mpid.append(name.split("@")[0]); // 提取进程ID部分 } ``` - **计算哈希值并取模**: 将该字符串转换为哈希(hashCode),取低16位(0xffff),再对最大workerId加1取模,得到最终的workerId。 - 数学公式: 设最大workerId为 $ \text{maxWorkerId} $,则: $$ \text{workerId} = (\text{mpid.toString().hashCode()} \,\&\, \text{0xffff}) \mod (\text{maxWorkerId} + 1) $$ - $\,\&\, 0xffff$ 确保只保留哈希的低16位(范围0-65535)。 - $\mod (\text{maxWorkerId} + 1)$ 将值映射到允许的workerId范围内(例如0-1023)。 示例代: ```java return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1); ``` 这一策略利用JVM进程ID的随机性,在分布式环境中降低冲突概率[^1]。 3. **注意事项**: - **冲突风险**:如果多个节点在同一数据中心共享相同的进程ID或哈希冲突,可能导致workerId重复。建议在容器化环境(如Docker)中手动配置workerId。 - **优化方案**:一些框架(如MyBatis-Plus)允许通过配置文件或环境变量覆盖workerId,避免哈希计算的不确定性[^3]。 - **唯一性保障**:workerId需与datacenterId配合使用,datacenterId通常通过机器MAC地址或配置中心生成(例如取MAC地址的哈希值)。 通过这种策略,雪花算法能在分布式系统中高效生成可排序的全局唯一ID,支撑高并发业务[^1][^3]。如果需要完整示例实现,可以参考开源项目如Hutool或Twitter的官方库。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值