ZBLOG

golang 实现雪花Id

雪花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的唯一性。

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://golang.0voice.com/?id=2424

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?