雪花Id是Twitter提出的一种分布式唯一ID生成算法,可以使用golang实现。
具体实现如下:
package main
import (
"fmt"
"math/rand"
"strconv"
"sync"
"time"
)
// 定义常量
const (
workerIdBits = 5
datacenterIdBits = 5
sequenceBits = 12
maxWorkerId = -1 ^ (-1 << workerIdBits) // 31
maxDatacenterId = -1 ^ (-1 << datacenterIdBits) // 31
timeLeftShift = sequenceBits + workerIdBits + datacenterIdBits
workerLeftShift = sequenceBits
datacenterLeftShift = sequenceBits + workerIdBits
sequenceMask = -1 ^ (-1 << sequenceBits) // 4095
)
type Snowflake struct {
mutex sync.Mutex
startTime int64
datacenterId int64
workerId int64
sequence int64
}
func NewSnowflake(datacenterId, workerId int64) *Snowflake {
if datacenterId < 0 || datacenterId > maxDatacenterId {
panic(fmt.Sprintf("datacenter Id can't be greater than %d or less than 0", maxDatacenterId))
}
if workerId < 0 || workerId > maxWorkerId {
panic(fmt.Sprintf("worker Id can't be greater than %d or less than 0", maxWorkerId))
}
return &Snowflake{
startTime: getTime(),
datacenterId: datacenterId,
workerId: workerId,
sequence: 0,
}
}
func (sf *Snowflake) GetId() int64 {
sf.mutex.Lock()
defer sf.mutex.Unlock()
now := getTime()
if now < sf.startTime {
panic(fmt.Sprintf("Clock moved backwards. Refusing to generate id for %d milliseconds", sf.startTime-now))
}
if now == sf.startTime {
sf.sequence = (sf.sequence + 1) & sequenceMask
if sf.sequence == 0 {
now = getNextTime(sf.startTime)
}
} else {
sf.sequence = 0
}
sf.startTime = now
return (now-sf.startTime)<<timeLeftShift | sf.datacenterId<<datacenterLeftShift |
sf.workerId<<workerLeftShift | sf.sequence
}
func getTime() int64 {
return time.Now().UnixNano() / int64(time.Millisecond)
}
func getNextTime(startTime int64) int64 {
timestamp := getTime()
for timestamp <= startTime {
timestamp = getTime()
}
return timestamp
}
func main() {
rand.Seed(time.Now().UnixNano())
datacenterId := rand.Int63n(maxDatacenterId)
workerId := rand.Int63n(maxWorkerId)
snowflake := NewSnowflake(datacenterId, workerId)
for i := 0; i < 10; i++ {
fmt.Println(strconv.FormatInt(snowflake.GetId(), 10))
}
}
在main函数中,我们使用rand模块来随机生成datacenterId和workerId。然后通过NewSnowflake方法创建一个新的Snowflake实例。
调用GetId方法可以获得一个新的雪花ID。
注意:本示例中,为了方便演示,我们将时间戳精确到毫秒级别,但实际应用中建议将时间戳精确到微秒或纳秒级别来提高ID的唯一性。