183 lines
3.6 KiB
Go
183 lines
3.6 KiB
Go
|
|
/**
|
|||
|
|
* package utils
|
|||
|
|
* 作用:雪花ID生成器,生成全局唯一的ID
|
|||
|
|
* 说明:使用Twitter的雪花算法,生成64位整数ID
|
|||
|
|
*/
|
|||
|
|
package utils
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"errors"
|
|||
|
|
"sync"
|
|||
|
|
"time"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
const (
|
|||
|
|
// 时间戳占用位数(41位,可以使用69年)
|
|||
|
|
timestampBits = 41
|
|||
|
|
// 数据中心ID占用位数(5位,最多32个数据中心)
|
|||
|
|
datacenterIDBits = 5
|
|||
|
|
// 机器ID占用位数(5位,每个数据中心最多32台机器)
|
|||
|
|
machineIDBits = 5
|
|||
|
|
// 序列号占用位数(12位,每毫秒最多4096个ID)
|
|||
|
|
sequenceBits = 12
|
|||
|
|
|
|||
|
|
// 最大值
|
|||
|
|
maxDatacenterID = -1 ^ (-1 << datacenterIDBits)
|
|||
|
|
maxMachineID = -1 ^ (-1 << machineIDBits)
|
|||
|
|
maxSequence = -1 ^ (-1 << sequenceBits)
|
|||
|
|
|
|||
|
|
// 位移
|
|||
|
|
machineIDShift = sequenceBits
|
|||
|
|
datacenterIDShift = sequenceBits + machineIDBits
|
|||
|
|
timestampShift = sequenceBits + machineIDBits + datacenterIDBits
|
|||
|
|
|
|||
|
|
// 起始时间戳(2024-01-01 00:00:00)
|
|||
|
|
epoch int64 = 1704067200000
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// Snowflake 雪花ID生成器
|
|||
|
|
type Snowflake struct {
|
|||
|
|
mutex sync.Mutex
|
|||
|
|
datacenterID int64
|
|||
|
|
machineID int64
|
|||
|
|
sequence int64
|
|||
|
|
lastStamp int64
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var (
|
|||
|
|
// 全局雪花ID生成器实例
|
|||
|
|
globalSnowflake *Snowflake
|
|||
|
|
once sync.Once
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* InitSnowflake
|
|||
|
|
* 功能:初始化全局雪花ID生成器
|
|||
|
|
* @param datacenterID 数据中心ID(0-31)
|
|||
|
|
* @param machineID 机器ID(0-31)
|
|||
|
|
*/
|
|||
|
|
func InitSnowflake(datacenterID, machineID int64) error {
|
|||
|
|
if datacenterID < 0 || datacenterID > maxDatacenterID {
|
|||
|
|
return errors.New("datacenter ID must be between 0 and 31")
|
|||
|
|
}
|
|||
|
|
if machineID < 0 || machineID > maxMachineID {
|
|||
|
|
return errors.New("machine ID must be between 0 and 31")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
once.Do(func() {
|
|||
|
|
globalSnowflake = &Snowflake{
|
|||
|
|
datacenterID: datacenterID,
|
|||
|
|
machineID: machineID,
|
|||
|
|
sequence: 0,
|
|||
|
|
lastStamp: -1,
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* NextID
|
|||
|
|
* 功能:生成下一个ID
|
|||
|
|
* @returns 64位整数ID
|
|||
|
|
*/
|
|||
|
|
func NextID() (int64, error) {
|
|||
|
|
if globalSnowflake == nil {
|
|||
|
|
// 默认使用datacenterID=1, machineID=1
|
|||
|
|
if err := InitSnowflake(1, 1); err != nil {
|
|||
|
|
return 0, err
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return globalSnowflake.nextID()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* nextID
|
|||
|
|
* 功能:生成下一个ID(内部方法)
|
|||
|
|
*/
|
|||
|
|
func (s *Snowflake) nextID() (int64, error) {
|
|||
|
|
s.mutex.Lock()
|
|||
|
|
defer s.mutex.Unlock()
|
|||
|
|
|
|||
|
|
now := time.Now().UnixMilli()
|
|||
|
|
|
|||
|
|
// 如果当前时间小于上次时间,说明时钟回拨
|
|||
|
|
if now < s.lastStamp {
|
|||
|
|
return 0, errors.New("clock moved backwards")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果是同一毫秒内
|
|||
|
|
if now == s.lastStamp {
|
|||
|
|
s.sequence = (s.sequence + 1) & maxSequence
|
|||
|
|
// 序列号溢出,等待下一毫秒
|
|||
|
|
if s.sequence == 0 {
|
|||
|
|
now = s.waitNextMillis(s.lastStamp)
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
// 新的毫秒,序列号重置
|
|||
|
|
s.sequence = 0
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
s.lastStamp = now
|
|||
|
|
|
|||
|
|
// 生成ID
|
|||
|
|
id := ((now - epoch) << timestampShift) |
|
|||
|
|
(s.datacenterID << datacenterIDShift) |
|
|||
|
|
(s.machineID << machineIDShift) |
|
|||
|
|
s.sequence
|
|||
|
|
|
|||
|
|
return id, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* waitNextMillis
|
|||
|
|
* 功能:等待下一毫秒
|
|||
|
|
*/
|
|||
|
|
func (s *Snowflake) waitNextMillis(lastStamp int64) int64 {
|
|||
|
|
now := time.Now().UnixMilli()
|
|||
|
|
for now <= lastStamp {
|
|||
|
|
now = time.Now().UnixMilli()
|
|||
|
|
}
|
|||
|
|
return now
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* NextIDString
|
|||
|
|
* 功能:生成下一个ID(字符串格式)
|
|||
|
|
*/
|
|||
|
|
func NextIDString() (string, error) {
|
|||
|
|
id, err := NextID()
|
|||
|
|
if err != nil {
|
|||
|
|
return "", err
|
|||
|
|
}
|
|||
|
|
return int64ToString(id), nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* int64ToString
|
|||
|
|
* 功能:将int64转换为字符串
|
|||
|
|
*/
|
|||
|
|
func int64ToString(id int64) string {
|
|||
|
|
if id == 0 {
|
|||
|
|
return "0"
|
|||
|
|
}
|
|||
|
|
negative := id < 0
|
|||
|
|
if negative {
|
|||
|
|
id = -id
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var result []byte
|
|||
|
|
for id > 0 {
|
|||
|
|
result = append([]byte{byte('0' + id%10)}, result...)
|
|||
|
|
id /= 10
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if negative {
|
|||
|
|
result = append([]byte{'-'}, result...)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return string(result)
|
|||
|
|
}
|
|||
|
|
|