分布式集群中雪花 ID 重复?三招教你彻底避坑!实战经验 + 解决方案
背景:一次离奇的主键重复事故
某天线上日志偶尔报错: “主键重复” 。一个看似简单的业务场景——APP 持续上传信息,用户量不足 1W,并发量极低,仅涉及单表插入操作。
然而,就是这个简单的 insert,却让团队排查到怀疑人生……
问题定位:
项目基于 SpringCloud+MybatisPlus,主键默认使用雪花 ID(Snowflake)。排查发现,生产环境部署了分布式集群(A/B/C 多台机器),但未配置 workId。
最终结论:多台机器因 workId 相同,导致生成的雪花 ID 发生碰撞。
知识卡:什么是雪花 ID?
核心原理
Snowflake 是 Twitter 开源的分布式 ID 生成算法,生成 64 位 Long 型 ID,结构如下:
0 | 时间戳(41位) | 数据中心ID(5位) | 机器ID(5位) | 序列号(12位)
优点
高性能: 单机每秒可生成 26 万+ ID。
趋势递增: 整体有序,适合数据库索引。
去中心化: 无需依赖
Redis/Zookeeper
,本地生成。
致命缺点
时钟回拨: 服务器时间倒退会导致 ID 重复。
机器 ID 冲突: 分布式环境下,若 workId 重复,ID 必然重复。
ID 不连续: 高并发时可能出现“跳号”。
避坑指南:如何确保 workId 全局唯一?
方案 1:IP 动态计算(推荐)
利用服务器 IP 最后一段取模,自动分配 workId:
优点: 无需人工干预,IP 天然唯一。
注意: 需确保 IP 末段不重复,适用于静态 IP 环境。
方案 2:环境变量注入(Docker 友好)
通过启动命令注入 workId:
适用场景: 容器化部署,灵活可控。
方案 3:中间件托管(高可用场景)
使用 Redis 或配置中心(如 Nacos)维护 workId 映射表:
优点: 适合动态扩缩容,避免 IP 变化引发问题。
实战代码:MybatisPlus 动态配置 workId
代码要点:
环境变量优先级 > IP 计算 > 默认值兜底。
日志告警:IP 获取失败时需人工介入。
总结:分布式 ID 设计的核心原则
全局唯一: 确保 workId 在集群内绝对不重复。
容错机制: 时钟回拨、IP 变更等场景需有兜底策略。
可观测性: 关键节点增加日志监控,如 workId 生成过程。
延伸思考:
若服务规模超 32 台(5 位 workId 上限),如何扩展?
如何结合 Leaf、UUID 等方案实现多级容灾?
评论