グローバルIDジェネレータ
3302 ワード
snowflakeの構造は以下の通りです.(部分的には-分離):0-000000 000 0000-0000 0-0000-00000第1位は未使用で、次の41位はミリ秒レベルの時間(41ビットの長さは69年まで使用可能)、そして5ビットのdatacenterIdと5ビットのworkId(10ビットの長さは1024ビットまでサポートされています.最後のノードです.)(12ビットのカウント番号は、各ノードがミリ秒ごとに4096個のID番号を生成することをサポートしています.)
全部合わせて64桁になります.Longタイプです.(文字列に変換したら最大19)
例:
全部合わせて64桁になります.Longタイプです.(文字列に変換したら最大19)
例:
currWoker := &idworker.IdWorker{}
currWoker.InitIdWorker(1000, 1)
newId , newIdErr:= currWoker.NexiId()
ソースコードは以下の通りですpackage idworker
import (
"errors"
"fmt"
"sync"
"time"
)
type IdWorker struct {
startTime int64
workerIdBits uint
datacenterIdBits uint
maxWorkerId int64
maxDatacenterId int64
sequenceBits uint
workerIdLeftShift uint
datacenterIdLeftShift uint
timestampLeftShift uint
sequenceMask int64
workerId int64
datacenterId int64
sequence int64
lastTimestamp int64
signMask int64
idLock *sync.Mutex
}
func (this *IdWorker) InitIdWorker(workerId, datacenterId int64) error {
var baseValue int64 = -1
this.startTime = 1463834116272
this.workerIdBits = 5
this.datacenterIdBits = 5
this.maxWorkerId = baseValue ^ (baseValue << this.workerIdBits)
this.maxDatacenterId = baseValue ^ (baseValue << this.datacenterIdBits)
this.sequenceBits = 12
this.workerIdLeftShift = this.sequenceBits
this.datacenterIdLeftShift = this.workerIdBits + this.workerIdLeftShift
this.timestampLeftShift = this.datacenterIdBits + this.datacenterIdLeftShift
this.sequenceMask = baseValue ^ (baseValue << this.sequenceBits)
this.sequence = 0
this.lastTimestamp = -1
this.signMask = ^baseValue + 1
this.idLock = &sync.Mutex{}
if this.workerId < 0 || this.workerId > this.maxWorkerId {
return errors.New(fmt.Sprintf("workerId[%v] is less than 0 or greater than maxWorkerId[%v].", workerId, datacenterId))
}
if this.datacenterId < 0 || this.datacenterId > this.maxDatacenterId {
return errors.New(fmt.Sprintf("datacenterId[%d] is less than 0 or greater than maxDatacenterId[%d].", workerId, datacenterId))
}
this.workerId = workerId
this.datacenterId = datacenterId
return nil
}
func (this *IdWorker) NextId() (int64, error) {
this.idLock.Lock()
timestamp := time.Now().UnixNano()
if timestamp < this.lastTimestamp {
return -1, errors.New(fmt.Sprintf("Clock moved backwards. Refusing to generate id for %d milliseconds", this.lastTimestamp-timestamp))
}
if timestamp == this.lastTimestamp {
this.sequence = (this.sequence + 1) & this.sequenceMask
if this.sequence == 0 {
timestamp = this.tilNextMillis()
this.sequence = 0
}
} else {
this.sequence = 0
}
this.lastTimestamp = timestamp
this.idLock.Unlock()
id := ((timestamp - this.startTime) << this.timestampLeftShift) |
(this.datacenterId << this.datacenterIdLeftShift) |
(this.workerId << this.workerIdLeftShift) |
this.sequence
if id < 0 {
id = -id
}
return id, nil
}
func (this *IdWorker) tilNextMillis() int64 {
timestamp := time.Now().UnixNano()
if timestamp <= this.lastTimestamp {
timestamp = time.Now().UnixNano() / int64(time.Millisecond)
}
return timestamp
}