不能直接用math/rand生成唯一id,因其无种子时输出固定、设纳秒种子在高并发下仍易碰撞;真正需确定性+分布式安全+无锁组合,推荐github.com/google/uuid(v4加密随机)或github.com/bwmarrin/snowflake(整数有序)。

为什么不能直接用 math/rand 生成唯一ID
因为 math/rand 默认不带种子,多次调用会重复输出相同序列;即使手动设种子(比如 rand.Seed(time.Now().UnixNano())),在高并发或短时高频调用下仍可能碰撞。真正需要的是「确定性+分布式安全+无锁」的组合,不是随机数。
github.com/sony/gobreaker 不是你要找的,该用 github.com/google/uuid
别被名字误导——gobreaker 是熔断器库,和 ID 无关。真正稳定、广泛验证过的方案是 github.com/google/uuid。它默认生成 v4 UUID(基于加密安全随机数),单机每秒几万次调用也几乎不会重复。
- 安装:
go get github.com/google/uuid - 基础用法:
uuid.New().String()→ 返回类似"f47ac10b-58cc-4372-a567-0e02b2c3d479" - 若需更紧凑格式(去掉连字符):
uuid.New().URN()[9:]或手动strings.ReplaceAll(uuid.New().String(), "-", "")
需要数字型递增 ID?用 github.com/bwmarrin/snowflake
当业务要求 ID 是整数、时间有序、可排序(比如作为数据库主键或分页依据),UUID 就不太合适。Snowflake 是事实标准:41bit 时间戳 + 10bit 机器 ID + 12bit 序列号,保证全局唯一且趋势递增。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 初始化必须指定节点 ID:
node, _ := snowflake.NewNode(1),不同服务实例要配不同int64值 - 生成:
node.Generate().Int64()→ 返回如1234567890123456789 - 注意:系统时间回拨会导致 panic,默认不处理;生产环境建议加
node.SetEpoch()并监控时钟同步
自己手写 ID 生成器?小心时钟精度和竞争条件
有人想用 atomic + time.Now().UnixMilli() 拼接自增序号,但实际极易出错:
- Linux 上
UnixMilli()实际精度常为 10–15ms,同一毫秒内并发调用必然冲突 - 哪怕加
sync.Mutex,也会成为性能瓶颈,QPS 上不去 - 跨进程/容器部署时,机器间时钟不同步会让“时间+序号”逻辑彻底失效
除非你控制全部部署环境(单机、低并发、不扩容),否则不要碰这种轮子。UUID 和 Snowflake 已覆盖 99% 场景,它们的边界和缺陷文档里都写清楚了——先吃透再替换。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










