直接用snowflakeidgenerator类易出错,根本原因是未保证workerid和datacenterid全局唯一;需用redis等中心化服务动态分配,统一用datetimeoffset.utcnow.tounixtimemilliseconds()防时钟回拨,sequence溢出时应阻塞等待而非重置。
为什么直接用 SnowflakeIdGenerator 类容易出错
很多人照着网上的 C# 雪花算法实现抄一个 SnowflakeIdGenerator 类,运行起来 ID 看似递增,但一上多节点就重复——根本原因是没处理好 **机器 ID(workerId)和数据中心 ID(datacenterId)的全局唯一分配**。雪花算法要求同一毫秒内,不同节点的 workerId 必须不重叠,否则 timestamp + workerId + sequence 组合就可能碰撞。
常见错误包括:
- 硬编码
workerId = 1,本地跑得通,部署到 3 台服务器全设成 1,必然冲突 - 用 IP 哈希取模算
workerId,但 IPv4 地址段有限,哈希后碰撞概率高 - 依赖配置文件手动填
workerId,运维漏配或填错,服务启动失败或 ID 冲突静默发生
用 ZooKeeper 或 Redis 自动分配 workerId 更可靠
生产环境推荐用中心化协调服务动态分配,避免人工干预。Redis 是多数团队已有组件,接入成本低:
- 每个实例启动时,用 Lua 脚本在 Redis 中原子性地申请一个未被占用的
workerId(比如从 0–1023 范围取) - 成功后写入临时 key(带 TTL),并监听该 key 过期或主动释放
- 若申请不到可用 ID,应阻塞等待或快速失败,不能降级为随机数——那就不叫雪花算法了
示例 Lua 脚本逻辑(用于 redis-cli --eval):