snowflake id 不严格有序,因其仅保证时间维度大致有序:同毫秒内序列号自增,但跨机器或时钟回拨会导致跳变或倒流;new snowflake(1,1)中两参数为数据中心id和机器id,合占10位、须全局唯一;时钟回拨应启用容忍机制并禁用ntp step模式;mybatis-plus的assign_snowflake默认不支持集群,需外置分配workerid。

为什么直接用 Snowflake 生成的 ID 不一定“有序”?
很多人以为 Snowflake 天然全局递增,其实它只保证“时间维度上大致有序”,不是严格单调递增。核心原因是:同一毫秒内,序列号(sequence)从 0 开始自增,但一旦跨机器或时钟回拨,就可能出现 ID 跳变甚至倒流。
常见错误现象:SELECT id FROM table ORDER BY id DESC 查出的最新记录,偶尔比前一条小;分库分表按 ID 取模后数据分布不均;下游系统依赖“ID 大 → 时间新”做排序,结果出错。
- 关键点:ID 的高位是时间戳(毫秒),中间是机器 ID,低位是序列号 —— 所以只要时钟没回拨、单机序列没溢出,同机器下 ID 是严格递增的
- 但多机环境下,A 机器在 t 毫秒生成了
1234567890123456789,B 机器在 t+1 毫秒生成的 ID 可能因机器 ID 更大而远大于它,也可能因序列号极小(比如 0)而只比它大一点点 —— 这就是“大致有序”的来源 - 如果业务强依赖严格递增(比如金融流水号),得额外加锁或改用数据库自增 + 缓存预分配,
Snowflake本身不解决这个问题
new Snowflake(1, 1) 中两个参数到底代表什么?
不同实现里参数含义容易混淆。以 Twitter 原版和主流 Java 实现(如 twitter-snowflake 或 mybatis-plus 内置)为例,new Snowflake(datacenterId, machineId) 是常见签名,但注意:
-
datacenterId和machineId合起来唯一标识一台发号机器 —— 它们不是“数据中心编号”和“服务器编号”的业务含义,而是用来填充 ID 中固定长度的机器位(通常各占 5 位,共 10 位,支持最多 1024 台机器) - 这两个值必须在部署范围内全局不重复,否则会生成重复 ID;但也不必严格按物理位置划分,可以用 IP 哈希、配置中心分配等方式动态获取
- 别硬编码成
new Snowflake(1, 1)上生产 —— 所有实例都用相同 ID,等于把分布式退化成单点,序列号一溢出就崩
示例:一台服务启动时从配置中心拉取 machine.id=17,然后调用 new Snowflake(0, 17)(假设不用数据中心位,就把 datacenterId 固定为 0)。
时钟回拨导致 Invalid System Clock 怎么办?
这是 Snowflake 最典型的线上故障:服务器时间被 NTP 同步或运维误操作向后/向前调整,导致当前时间小于上次生成 ID 用的时间戳,算法直接抛异常或阻塞等待。
- 根本原因:为了保证单调性,
Snowflake会校验currentTimestamp >= lastTimestamp,不满足就报Invalid System Clock - 不要简单 catch 异常然后 sleep —— 如果回拨 5 秒,sleep 5 秒会导致服务卡死,且无法解决根本问题
- 更稳妥的做法是:启用容忍机制(如
waitIfClockBackwards配置),允许短时回拨(比如 10ms 内)自动等待;对长时回拨,应告警并人工介入,而不是静默降级 - 生产环境务必关闭 NTP 的 step 模式(即不允许跳变),改用 slewing 模式缓慢校准;容器环境尤其要注意宿主机时间同步策略
Java 里用 MyBatis-Plus 的 IdType.ASSIGN_SNOWFLAKE 安全吗?
安全,但前提是理解它背后的默认行为 —— 它用的是 DefaultIdentifierGenerator,基于 System.currentTimeMillis() + 进程内原子计数器 + JVM 启动时随机生成的 workerId,**不支持集群多实例唯一**。
- 问题场景:Spring Boot 多节点部署,每个节点都用
ASSIGN_SNOWFLAKE,workerId 默认由Random生成,大概率重复 → ID 冲突风险极高 - 解决方案:必须重写
IdentifierGenerator,把workerId改成从外部获取(如 Redis 自增、ZooKeeper 顺序节点、配置中心下发) - 性能影响:每次生成 ID 都走一次 Redis?别这么做。推荐启动时一次性分配并缓存,后续纯内存计算 ——
Snowflake的价值就在无锁、低延迟,别自己拖慢它
真正要上生产,别图省事直接开箱即用;ID 是数据链路的基石,机器 ID 的分配逻辑必须和你的部署拓扑对齐。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











