Documentation
¶
Overview ¶
Package uidgen 提供分布式唯一 ID 生成器.
推荐使用 Snowflake(全局单例 + 极简 API):
uidgen.InitSnowflake(7) // 一次性初始化, machineID ∈ [0, 1023] id := uidgen.SnowflakeID() // int64, 不返错, auto-init 兜底 uidgen.ExtractSnowflakeTime(id) // epoch = 2025-01-01 uidgen.ExtractSnowflakeMachineID(id) uidgen.ExtractSnowflakeSequence(id)
Extract 函数(epoch = 2024-01-01)用于从旧式 ID 中提取元数据:
uidgen.ExtractTime(id) uidgen.ExtractWorkerID(id) uidgen.ExtractSequence(id)
UUID 系列(与 Snowflake 无关)见 uuid.go.
ULID 系列(26 字符,字典序 == 时间序)见 ulid.go——面向「文本主键 + 按 ID 做时间序 range scan」的场景:
id := uidgen.ULID() // 26 字符,同毫秒内严格递增 uidgen.ULIDFromTime(t) // 指定时间戳(按业务时间回填) ts, entropy, err := uidgen.ParseULID(id) // 解回时间戳与 80 bit 熵
crypto/rand 随机串生成(标识符/密钥面):与 Snowflake(可预测、仅作 ID)分居—— 密钥、一次性凭据、高熵标识符必须走本文件。
Index ¶
- Variables
- func ExtractSequence(id int64) int64
- func ExtractSnowflakeMachineID(id int64) int64
- func ExtractSnowflakeSequence(id int64) int64
- func ExtractSnowflakeTime(id int64) time.Time
- func ExtractTime(id int64) time.Time
- func ExtractWorkerID(id int64) int64
- func InitSnowflake(machineID int64) error
- func InitSnowflakeFromEnv() error
- func InitSnowflakeWith(machineID int64, opts ...SnowflakeOption) error
- func ParseULID(s string) (time.Time, []byte, error)
- func RandomHex(nBytes int) string
- func RandomHexE(nBytes int) (string, error)
- func RandomHexFrom(r io.Reader, nBytes int) (string, error)
- func RandomString(alphabet string, n int) string
- func RandomStringE(alphabet string, n int) (string, error)
- func RandomStringFrom(r io.Reader, alphabet string, n int) (string, error)
- func ShortUUID() string
- func ShortUUIDToUpper() string
- func SnowflakeID() int64
- func SnowflakeMachineID() int64
- func ULID() string
- func ULIDFromTime(t time.Time) string
- func UUID() string
- func UUIDToUpper() string
- func UUIDWithHyphen() string
- type Snowflake
- type SnowflakeOption
Constants ¶
This section is empty.
Variables ¶
var ErrInvalidULID = errors.New("uidgen: invalid ULID")
ErrInvalidULID 表示字符串不是合法 ULID:长度不对、含非法字符, 或超出 128 bit 范围(首字符取值大于 '7')。
调用方用 errors.Is(err, uidgen.ErrInvalidULID) 判定;具体原因在错误消息里。
Functions ¶
func ExtractSnowflakeMachineID ¶
ExtractSnowflakeMachineID 从 Snowflake ID 中提取 machineID.
func ExtractSnowflakeSequence ¶
ExtractSnowflakeSequence 从 Snowflake ID 中提取 sequence.
func ExtractSnowflakeTime ¶
ExtractSnowflakeTime 从 Snowflake ID 中提取生成时间. 注意:与 ExtractTime 不可混用——epoch 不同(2025 vs 2024).
func InitSnowflake ¶
InitSnowflake 初始化全局 Snowflake singleton(缺省容忍上限 5s,无回拨回调). machineID 必须在 [0, 1023] 范围. 多次调用:第一次生效,后续返错(防止误用).
并发安全:CAS(nil -> s) 失败表示已初始化,Load() 拿到的是上次成功的实例.
func InitSnowflakeFromEnv ¶
func InitSnowflakeFromEnv() error
InitSnowflakeFromEnv 从 MACHINE_ID env 读 machineID,解析失败兜底 0. 单进程 dev / 测试默认 0 够用;生产必须显式注入(e.g. docker-compose 配 0/1/2).
func InitSnowflakeWith ¶ added in v0.4.2
func InitSnowflakeWith(machineID int64, opts ...SnowflakeOption) error
InitSnowflakeWith 带选项初始化全局 Snowflake singleton(#72): WithClockBackTolerance 调时钟回拨容忍上限、WithOnClockBack 注册大幅回拨 通报回调。machineID 范围与多次调用规则同 InitSnowflake.
func ParseULID ¶ added in v0.3.0
ParseULID 解析 ULID,返回它的毫秒时间戳与 80 bit 熵(10 字节)。
大小写不敏感(ULID 规范如此)。长度不对、含非法字符、或超出 128 bit (首字符取值大于 '7')时返回包装了 ErrInvalidULID 的错误。
func RandomHex ¶
RandomHex n 字节 crypto/rand 随机数的十六进制串(2n 字符)。 nBytes <= 0 直接 panic(#50):对标识符场景「非法长度=调用方 bug」,对密钥/ 凭据场景静默空串是**最危险的缺省**——「名义生成了、实际是空钥匙」(空串做 HMAC key / API token 落库后患无穷),与 RandomString 空 alphabet 的防呆哲学 对齐:非法入参启动即暴露好过静默降级。长度来自配置面时请在构造期校验。 crypto/rand 读取失败(运行期环境故障)同样 panic——请求路径请用 RandomHexE(#87)。
适用:对象 ID、webhook secret、审批 HMAC 密钥等高熵标识符与密钥面。
func RandomHexE ¶ added in v0.5.0
RandomHexE 是 RandomHex 的 error 返回变体(#87):入参校验与 RandomHex 完全 一致(nBytes <= 0 仍 panic——非法入参是调用方 bug,防呆哲学不变);差异仅在 crypto/rand 读取失败这一**运行期环境故障**——panic 版会把它升级成进程崩溃, 本版返回 error,请求路径(nonce/token/上传会话 ID)可就地降级处理,不必再因 「没有 error 出口」而吞错或自己手搓 make+rand.Read+hex。
func RandomHexFrom ¶ added in v0.5.0
RandomHexFrom 是 RandomHex 的显式随机源变体(#87):从 r 读满 nBytes 字节后 hex 编码,专供测试注入确定性/必然失败的随机源(也供调用方自带可信随机源)。 入参校验与 RandomHex 同款(nBytes <= 0 panic,checkHexArgs 单一来源);nil reader 视为非法入参 panic——显式源是调用方的承诺,nil 不是「用默认」。 读取语义 io.ReadFull:注入短读 reader(如每次只吐 3 字节)循环读满。
func RandomString ¶
RandomString 从 alphabet 均匀采样 n 个字符(rune 语义:多字节 alphabet 产出 合法 UTF-8,输出恰含 n 个字符;#89)——拒绝采样消模偏差,无 mod 偏置。
入参防呆(全部当场 panic):
- n <= 0 直接 panic(#88):与 #50 对 RandomHex 的修法同口径——空串密钥是 最危险的缺省(「名义生成了、实际是空钥匙」),长度来自配置面时请在构造 期校验;
- alphabet 为空 panic;
- alphabet 字符数 > 256 panic(#52:拒绝采样 maxMultiple 归 0 ⇒ 死循环; #89 起判据按 rune 数计,字节口径下的多字节大字符集不再被误伤)。
crypto/rand 读取失败(运行期环境故障)同样 panic——请求路径请用 RandomStringE(#87)。 适用:带自定义字符集的短 ID/令牌。
func RandomStringE ¶ added in v0.5.0
RandomStringE 是 RandomString 的 error 返回变体(#87):入参校验与 RandomString 完全一致(n <= 0 / 空 alphabet / 字符数 >256 仍 panic——非法入参是调用方 bug); 差异仅在 crypto/rand 读取失败这一运行期环境故障返回 error 而非 panic。取样经 共享核心 sampleRunes(显式随机源变体 RandomStringFrom 同款),拒绝采样实现 只此一份(无第二份 256%len 偏差修复代码)。
func RandomStringFrom ¶ added in v0.5.0
RandomStringFrom 是 RandomString 的显式随机源变体(#87):从 r 取样,与 RandomString/RandomStringE 共用同一份拒绝采样实现(sampleRunes,无第二份 256%len 偏差修复代码)。入参校验同 panic 版(n<=0 / 空 alphabet / 字符数 >256 panic,checkStringArgs 单一来源);nil reader 视为非法入参 panic。 读取语义 io.ReadFull:注入短读 reader(如每次只吐 3 字节)循环读满。
func SnowflakeID ¶
func SnowflakeID() int64
SnowflakeID 拿下一个 int64 ID. 未 InitSnowflake 时自动以 machineID=0 初始化.
并发说明:auto-init 路径在多 goroutine 同时首次调用时,CAS 失败的 goroutine 会回退到 Load() 读已 init 的实例,保证不会 nil deref.
时钟回拨(#72):回拨在容忍上限内(缺省 5s,InitSnowflakeWith + WithClockBackTolerance 可调)时持锁有界等待时钟追平;超限(如 NTP 大幅 回拨)转进位生成——以回拨前基准继续发号,不再阻塞,ID 时间戳领先真实 时钟直到追平(ExtractSnowflakeTime 读到的是合成时刻)。大幅回拨可用 WithOnClockBack 注册回调接告警.
func SnowflakeMachineID ¶
func SnowflakeMachineID() int64
SnowflakeMachineID 返当前 init 用的 machine ID,未初始化返 -1,测试用.
func ULID ¶ added in v0.3.0
func ULID() string
ULID 返回 26 字符的 ULID(Universally Unique Lexicographically Sortable Identifier)。
结构 = 48 bit 毫秒时间戳(Unix 纪元)+ 80 bit 熵,Crockford Base32 编码。 适用于「文本主键 + 按 ID 做时间序 range scan」这一类需求: Snowflake 是 int64(不能直接当文本主键),UUID 是随机串(字典序与时间无关)。
同一毫秒内进程内**严格单调**:熵逐个递增,80 bit 熵用尽则进位到下一毫秒。 时钟回拨时冻结在上一次的毫秒继续递增熵,保证不会出现更小的 ID。
零第三方依赖:crypto/rand + 标准库。
func ULIDFromTime ¶ added in v0.3.0
ULIDFromTime 用指定时间戳生成 ULID,便于按业务时间回填 ID。
时间戳取 t 的 Unix 毫秒;熵为随机值。**不参与 ULID() 的进程内单调序列** ——回填的业务时间可能早于当前时间,混进单调序列会破坏它的单调性。 同一 t 多次调用得到的 ULID 彼此无序,需要有序时请用 ULID()。
t 超出 48 bit 毫秒时间戳范围(Unix 纪元之前,或公元 10889 年之后)时 panic: 这种时间戳编不出合法 ULID,静默截断会得到一个「时间不对但看着正常」的 ID。
Types ¶
type Snowflake ¶
type Snowflake struct {
// contains filtered or unexported fields
}
Snowflake 是 singleton 模式的 Snowflake ID 生成器.
Bit 布局(bit 63 → 0):
[1 sign | 41 ts | 10 machine | 12 sequence]
= ~69 years × 1024 machines × 4096 IDs/ms per machine.
区别于旧式 ID 生成:
- Singleton 模式,业务侧直接调 SnowflakeID() 拿下一个 int64 ID.
- 时钟回拨不无限忙等(#72):容忍上限内(缺省 5s)持锁等时钟追平; 超限转进位生成(以回拨前基准继续发号),可注册 WithOnClockBack 告警.
- API 极简:InitSnowflake + SnowflakeID,不暴露 mu / sequence / lastTS.
并发模型:
- InitSnowflake 用 atomic.Pointer CAS 保证 "只 init 一次" + "成功后立刻可见".
- SnowflakeID() auto-init 路径在 CAS 失败时回退到 Load(),避免 nil deref.
- next() 持单 mu 串行:临界区短(同 ms 仅几次算术,跨 ms 持锁等下 ms 最坏 1ms).
Reference: https://github.com/twitter-archive/snowflake (Twitter, 2010)
type SnowflakeOption ¶ added in v0.4.2
type SnowflakeOption func(*Snowflake)
SnowflakeOption 是 Snowflake 生成器的配置选项(#72),经 InitSnowflakeWith 注入全局单例。
func WithClockBackTolerance ¶ added in v0.4.2
func WithClockBackTolerance(d time.Duration) SnowflakeOption
WithClockBackTolerance 设置时钟回拨容忍上限 d(缺省 5s,#72):回拨 ≤ d 时 维持既有行为——持锁等待时钟追平(最坏等满 d);回拨 > d 时不再等待,转 进位生成。d ≤ 0 表示任何回拨都直接进位生成。
func WithOnClockBack ¶ added in v0.4.2
func WithOnClockBack(fn func(back time.Duration)) SnowflakeOption
WithOnClockBack 注册大幅时钟回拨通报回调(#72):回拨幅度超过容忍上限时, 生成器放弃等待、转进位生成——ID 时间戳领先真实时钟直到追平,本回调以实际 回拨幅度 back 触发,每轮回拨(从进入进位生成到真实时钟追平)只触发一次。 未注册时缺省 slog.Warn。
回调在生成器持锁状态下同步调用,必须快速返回(记数/投递告警即可): 阻塞会卡住全进程的 ID 生成;再调 SnowflakeID/InitSnowflake 会死锁。