133 lines
3.5 KiB
Go
133 lines
3.5 KiB
Go
package uid
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"math"
|
||
"strconv"
|
||
"time"
|
||
|
||
"github.com/redis/go-redis/v9"
|
||
)
|
||
|
||
const (
|
||
Key = 1 // key码
|
||
BitsFull = 64 //
|
||
BitsPre = 1 // 固定
|
||
BitsTime = 41 // 毫秒时间戳 可以最多支持69年
|
||
BitsServer = 5 // 服务器最多支持32台
|
||
BitsWorker = 5 // 最多支持32种业务
|
||
BitsSequence = 12 // 一毫秒内支持4096个请求
|
||
OffsetTimestamp int64 = 1561910400000 // 时间戳起点时间毫秒 2019-07-01 00:00:00
|
||
)
|
||
|
||
type SignGenerator struct {
|
||
ServerID int
|
||
WorkerID int
|
||
RedisClient *redis.Client
|
||
}
|
||
|
||
func NewSignGenerator(redisClient *redis.Client) *SignGenerator {
|
||
return &SignGenerator{
|
||
RedisClient: redisClient,
|
||
}
|
||
}
|
||
|
||
func (sg *SignGenerator) GetNumber() (uint64, error) {
|
||
if sg.ServerID < 0 || sg.ServerID > 31 {
|
||
return 0, fmt.Errorf("serverID is lost")
|
||
}
|
||
if sg.WorkerID < 0 || sg.WorkerID > 31 {
|
||
return 0, fmt.Errorf("workerID is lost")
|
||
}
|
||
|
||
// redis报错等时最大5次retry就退出生成
|
||
maxRetryCount := 0
|
||
for {
|
||
if maxRetryCount > 5 {
|
||
return 0, fmt.Errorf("more than 5 times retry")
|
||
}
|
||
id := uint64(math.Pow(2, BitsFull-BitsPre)) << BitsPre
|
||
|
||
nowTime := time.Now().UnixNano() / int64(time.Millisecond)
|
||
startTime := OffsetTimestamp
|
||
diffTime := nowTime - startTime
|
||
shift := BitsFull - BitsPre - BitsTime
|
||
id |= uint64(diffTime << shift)
|
||
|
||
shift -= BitsServer
|
||
id |= uint64(sg.ServerID) << shift
|
||
|
||
shift -= BitsWorker
|
||
id |= uint64(sg.WorkerID) << shift
|
||
|
||
// 自增值
|
||
sequenceNumber := sg.getSequence(strconv.FormatUint(id, 10), 0)
|
||
|
||
if sequenceNumber > int64(math.Pow(2, BitsSequence)-1) {
|
||
time.Sleep(1 * time.Millisecond)
|
||
maxRetryCount++
|
||
} else {
|
||
id |= uint64(sequenceNumber)
|
||
return id, nil
|
||
}
|
||
}
|
||
}
|
||
|
||
func (sg *SignGenerator) GetServerID() int {
|
||
return sg.ServerID
|
||
}
|
||
|
||
func (sg *SignGenerator) SetServerID(serverID int) *SignGenerator {
|
||
sg.ServerID = serverID
|
||
return sg
|
||
}
|
||
|
||
func (sg *SignGenerator) GetWorkerID() int {
|
||
return sg.WorkerID
|
||
}
|
||
|
||
func (sg *SignGenerator) SetWorkerID(workerID int) *SignGenerator {
|
||
sg.WorkerID = workerID
|
||
return sg
|
||
}
|
||
|
||
func (sg *SignGenerator) getSequence(id string, level int) int64 {
|
||
// 嵌套大于50层时,返回最大序号
|
||
if level > 50 {
|
||
return int64(math.Pow(2, BitsSequence)) + 1
|
||
}
|
||
lua := `
|
||
local sequenceKey = KEYS[1]
|
||
local sequenceNumber = redis.call("incr", sequenceKey)
|
||
redis.call("pexpire", sequenceKey, 100)
|
||
return sequenceNumber
|
||
`
|
||
sequence, err := sg.RedisClient.Eval(context.Background(), lua, []string{id}, 1).Int64()
|
||
if err != nil {
|
||
fmt.Println("SignGenerator err", sequence, err, level)
|
||
return sg.getSequence(id, level+1)
|
||
}
|
||
return sequence
|
||
}
|
||
|
||
func (sg *SignGenerator) ReverseNumber(number uint64) map[string]interface{} {
|
||
uuidItem := make(map[string]interface{})
|
||
shift := BitsFull - BitsPre - BitsTime
|
||
uuidItem["diffTime"] = (number >> shift) & (uint64(math.Pow(2, BitsTime)) - 1)
|
||
|
||
shift -= BitsServer
|
||
uuidItem["serverId"] = (number >> shift) & (uint64(math.Pow(2, BitsServer)) - 1)
|
||
|
||
shift -= BitsWorker
|
||
uuidItem["workerId"] = (number >> shift) & (uint64(math.Pow(2, BitsWorker)) - 1)
|
||
|
||
shift -= BitsSequence
|
||
uuidItem["sequenceNumber"] = (number >> shift) & (uint64(math.Pow(2, BitsSequence)) - 1)
|
||
|
||
timestamp := int64(uuidItem["diffTime"].(uint64)/1000) + (OffsetTimestamp / 1000)
|
||
uuidItem["generateTime"] = time.Unix(timestamp, 0).Format("2006-01-02 15:04:05")
|
||
|
||
return uuidItem
|
||
}
|