package uid import ( "context" "fmt" "math" "os" "strconv" "sync/atomic" "time" "github.com/redis/go-redis/v9" ) const ( Order = 1 ) const ( 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 } var num int64 func GenerateNo() string { t := time.Now() s := t.Format("20060102150405") m := t.UnixNano()/1e6 - t.UnixNano()/1e9*1e3 ms := sup(m, 3) p := os.Getpid() % 1000 ps := sup(int64(p), 3) i := atomic.AddInt64(&num, 1) r := i % 10000 rs := sup(r, 4) n := fmt.Sprintf("%s%s%s%s", s, ms, ps, rs) return n } func sup(i int64, n int) string { m := fmt.Sprintf("%d", i) for len(m) < n { m = fmt.Sprintf("0%s", m) } return m }