package idgen import ( "sync" "time" ) const ( // int64EpochMs 使用固定业务纪元,缩短时间戳占用位数。 int64EpochMs int64 = 1704067200000 // maxInt64NodeID 预留 10 bit 给节点,支持 1024 个发号节点。 maxInt64NodeID int64 = 1023 // int64SequenceMask 预留 12 bit 给同毫秒序列。 int64SequenceMask int64 = 4095 ) // Int64Generator 生成 Snowflake-like int64 ID。 // 格式为 timestamp_ms | node_id | sequence,适合用户主键这种不可变长 ID。 type Int64Generator struct { mu sync.Mutex nodeID int64 lastMs int64 sequence int64 now func() time.Time sleepUntil func(time.Time) } // NewInt64Generator 创建用户主键发号器。 // nodeID 必须由部署配置保证不同发号节点不冲突。 func NewInt64Generator(nodeID int64) *Int64Generator { if nodeID < 0 { nodeID = 0 } if nodeID > maxInt64NodeID { nodeID = nodeID & maxInt64NodeID } return &Int64Generator{ nodeID: nodeID, now: time.Now, sleepUntil: defaultSleepUntil, } } // NewInt64 返回一个全局唯一倾向的 int64 ID。 func (g *Int64Generator) NewInt64() int64 { g.mu.Lock() defer g.mu.Unlock() nowMs := g.now().UnixMilli() if nowMs < g.lastMs { // 时钟回拨时等待到上次发号时间,避免生成倒退 ID。 g.sleepUntil(time.UnixMilli(g.lastMs)) nowMs = g.now().UnixMilli() } if nowMs == g.lastMs { g.sequence = (g.sequence + 1) & int64SequenceMask if g.sequence == 0 { // 同毫秒序列耗尽时等到下一毫秒再继续。 next := time.UnixMilli(g.lastMs + 1) g.sleepUntil(next) nowMs = g.now().UnixMilli() } } else { g.sequence = 0 } g.lastMs = nowMs return ((nowMs - int64EpochMs) << 22) | (g.nodeID << 12) | g.sequence } // defaultSleepUntil 封装真实等待,测试可通过结构体替换。 func defaultSleepUntil(target time.Time) { if delay := time.Until(target); delay > 0 { time.Sleep(delay) } }