0

0

Java面试——雪花算法生成全局唯一ID

月夜之吻

月夜之吻

发布时间:2026-03-11 12:37:38

|

815人浏览过

|

来源于php中文网

原创

雪花算法id不严格递增,因时钟回拨、机器时钟不同步或序列号重置会导致id跳变甚至变小;依赖其做时间排序易出错,强递增需求应改用号段模式或中心化id服务。

java面试——雪花算法生成全局唯一id

为什么雪花算法生成的ID不是严格递增的

雪花算法(Snowflake)生成的 long 类型ID,高位是时间戳,中间是机器ID,低位是序列号。它保证「同一毫秒内多个请求不重复」,但**不保证全局严格递增**——因为时间回拨、多台机器时钟不同步、或同一毫秒内序列号耗尽后跳到下一毫秒再重置序列号,都会导致ID“跳变”甚至“变小”。比如机器A在1712345678000毫秒末生成了1712345678000000002,机器B在1712345678001毫秒初生成了1712345678001000000,看起来递增;但如果B的时钟慢了2ms,它可能还在用1712345678000时间戳生成ID,此时就可能比A的ID小。

常见误用场景:直接拿雪花ID当MySQL主键并依赖ORDER BY id DESC做最新数据排序,在分布式写入+时钟偏差下会漏掉或错序。

  • 若需时间趋势大致有序,确保所有节点NTP同步,误差控制在10ms
  • 若强依赖严格递增,改用数据库自增+号段模式,或引入中心化ID服务(如Leaf)
  • 部分封装库(如Twitter Snowflake原版Java实现)默认不校验时钟回拨,需自行加锁等待或抛异常

Java中用ZooKeeper分配workerId容易踩哪些坑

雪花算法要求每台机器有唯一workerId(通常5位,支持最多32个节点)。用ZooKeeper自动分配看似合理,但实际落地常出问题:

  • ZK连接闪断时,应用可能重复注册/获取到相同workerId,导致ID冲突 —— 必须用临时顺序节点+watch机制,并在创建失败时主动退出而非重试
  • 容器化部署下,Pod重启IP可能不变但进程是新的,ZK节点未及时清除,造成“僵尸ID”被复用 —— 需结合hostname + processId生成ZK路径,或用K8s Downward API注入唯一标识
  • 本地开发时没连ZK,硬编码workerId=1上线后和其他机器撞了 —— 建议启动时校验:若从ZK获取失败,拒绝启动并打印明确错误,而不是fallback到默认值

更轻量的做法:用配置中心(如Nacos)预分配workerId,或启动参数传入(-Dsnowflake.workerId=5),避免运行时依赖外部服务。

星月写作
星月写作

专为网络小说、 剧本创作者打造的AI增效工具

下载

立即学习Java免费学习笔记(深入)”;

如何安全处理时钟回拨

服务器时间被人为调整或NTP校正时,可能导致雪花算法生成重复ID(因为时间戳变小,而序列号未归零)。原生Snowflake对回拨的处理策略直接影响可用性:

  • 直接抛异常(如RuntimeException("Clock moved backwards"))最安全,但业务请求会失败 —— 适合金融等强一致性场景
  • 阻塞等待(如循环Thread.sleep(1)直到时间追上)可能引发雪崩 —— 若回拨10秒,所有线程卡住,QPS归零
  • 使用“容忍窗口”:只对小于5ms的回拨等待,大于则抛异常 —— 需配合监控告警,快速发现时钟异常

推荐方案:

if (timestamp < lastTimestamp) {
    long offset = lastTimestamp - timestamp;
    if (offset <= 5) {
        try {
            Thread.sleep(offset << 1);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException(e);
        }
        timestamp = timeGen();
        if (timestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards more than 5ms");
        }
    } else {
        throw new RuntimeException("Clock moved backwards: " + offset + "ms");
    }
}

MyBatis插入时雪花ID被截断成0怎么办

Java里雪花ID是long(64位),但MySQL列类型若定义为INT(32位),插入时会被MySQL静默截断为0或最大值,且无报错。这是线上最隐蔽的ID污染问题之一。

  • 检查表结构:DESCRIBE table_name确认ID字段是BIGINT UNSIGNED(推荐)或至少BIGINT
  • MyBatis映射中,<result column="id" property="id" jdbctype="BIGINT"></result>必须显式指定jdbcType,否则某些驱动可能按int推导
  • Spring Boot配置spring.jpa.hibernate.ddl-auto=none,禁用自动建表,避免开发机生成错误schema带到生产

另一个常见点:前端JS处理ID时,Number精度只有53位,超过会丢失低位。传输ID务必用字符串,接口定义中@JsonSerialize(using = ToStringSerializer.class)别省略。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
mysql修改数据表名
mysql修改数据表名

MySQL修改数据表:1、首先查看数据库中所有的表,代码为:‘SHOW TABLES;’;2、修改表名,代码为:‘ALTER TABLE 旧表名 RENAME [TO] 新表名;’。php中文网还提供MySQL的相关下载、相关课程等内容,供大家免费下载使用。

686

2023.06.20

MySQL创建存储过程
MySQL创建存储过程

存储程序可以分为存储过程和函数,MySQL中创建存储过程和函数使用的语句分别为CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句调用存储过程智能用输出变量返回值。函数可以从语句外调用(通过引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。php中文网还提供MySQL创建存储过程的相关下载、相关课程等内容,供大家免费下载使用。

513

2023.06.21

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

287

2023.07.18

mysql密码忘了怎么查看
mysql密码忘了怎么查看

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql密码忘了怎么办呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

519

2023.07.19

mysql创建数据库
mysql创建数据库

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql怎么创建数据库呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

267

2023.07.25

mysql默认事务隔离级别
mysql默认事务隔离级别

MySQL是一种广泛使用的关系型数据库管理系统,它支持事务处理。事务是一组数据库操作,它们作为一个逻辑单元被一起执行。为了保证事务的一致性和隔离性,MySQL提供了不同的事务隔离级别。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

392

2023.08.08

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

542

2023.08.11

mysql忘记密码
mysql忘记密码

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。那么忘记mysql密码我们该怎么解决呢?php中文网给大家带来了相关的教程以及其他关于mysql的文章,欢迎大家前来学习阅读。

666

2023.08.14

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

3

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号