生成全局唯一ID的雪花算法原理
雪花算法是一種用于生成全局唯一ID的算法,最初由Twitter開發,用于解決分布式系統中生成ID的問題。其核心思想是將一個64位的長整型ID劃分成多個部分,每個部分用于表示不同的信息,確保了生成的ID在分布式環境下的唯一性。
ID結構
- 符號位(1位):始終為0,用于保證ID為正數。
- 時間戳(41位):表示生成ID的時間戳,精確到毫秒級。
- 工作節點ID(10位):表示生成ID的機器的唯一標識。
- 序列號(12位):表示在同一毫秒內生成的多個ID的序列號。
生成步驟
- 獲取當前時間戳,精確到毫秒級。
- 如果當前時間小于上次生成ID的時間,或者在同一毫秒內生成的ID數量超過最大值,等待下一毫秒再繼續生成。
- 如果當前時間等于上次生成ID的時間,序列號自增1。
- 如果當前時間大于上次生成ID的時間,序列號重新從0開始。
- 將各個部分的值組合,得到最終的64位ID。
Go實現雪花算法的高并發ID生成器
package mAIn
import (
"fmt"
"sync"
"time"
)
const (
workerBits = 10
sequenceBits = 12
workerMax = -1 ^ (-1 << workerBits)
sequenceMask = -1 ^ (-1 << sequenceBits)
timeShift = workerBits + sequenceBits
workerShift = sequenceBits
epoch = 1609459200000
)
type Snowflake struct {
mu sync.Mutex
lastTime int64
workerID int64
sequence int64
}
func NewSnowflake(workerID int64) *Snowflake {
if workerID < 0 || workerID > workerMax {
panic(fmt.Sprintf("worker ID must be between 0 and %d", workerMax))
}
return &Snowflake{
lastTime: time.Now().UnixNano() / 1e6,
workerID: workerID,
sequence: 0,
}
}
func (sf *Snowflake) NextID() int64 {
sf.mu.Lock()
defer sf.mu.Unlock()
currentTime := time.Now().UnixNano() / 1e6
if currentTime < sf.lastTime {
panic(fmt.Sprintf("clock moved backwards, refusing to generate ID for %d milliseconds", sf.lastTime-currentTime))
}
if currentTime == sf.lastTime {
sf.sequence = (sf.sequence + 1) & sequenceMask
if sf.sequence == 0 {
for currentTime <= sf.lastTime {
currentTime = time.Now().UnixNano() / 1e6
}
}
} else {
sf.sequence = 0
}
sf.lastTime = currentTime
id := (currentTime-epoch)<<timeShift | (sf.workerID << workerShift) | sf.sequence
return id
}
func main() {
sf := NewSnowflake(1) // 假設工作節點ID為1
for i := 0; i < 10; i++ {
id := sf.NextID()
fmt.Println(id)
time.Sleep(time.Millisecond)
}
}
高并發下的唯一性和遞增性保障
在高并發場景下,保障雪花算法生成的ID唯一性和遞增性的關鍵在于:
- 唯一性: 工作節點ID的設置保證了不同節點生成的ID不會沖突。序列號的自增和位運算保證了同一毫秒內生成的ID唯一。
- 遞增性: 在同一毫秒內生成的多個ID按序列號的遞增順序排列。即使在極端情況下,同一毫秒內生成的ID數量超過了最大值,會等待下一毫秒重新開始,也保證了遞增性。
總體來說,雪花算法在高并發下是一個可靠的ID生成方案。它的高性能和低碰撞概率使得它在分布式系統中被廣泛應用。