golang,go,博客,开源,编程
雪花算法 是一种分布式 ID 生成算法,它由 Twitter 在 2010 年提出,目的是为了解决分布式系统中 ID 生成的高并发、高可用性和高唯一性等问题。雪花算法基于 Twitter 的分布式系统需求,通过分布式生成全局唯一的 ID,用于避免数据库中自增主键的单点瓶颈问题,同时保证生成的 ID 在时间上的递增顺序。
雪花算法通过将 64 位的数字拆分成多个部分,每个部分有不同的含义。每一部分的位数定义了算法的结构和性能特点。通常情况下,雪花 ID 是一个 64 位的长整型(int64)数值,具体结构如下:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 1 bit | 41 bits | 10 bits | 12 bits | 1 bit |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| sign bit | timestamp | machine ID | data center ID | sequence ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0
,用来表示正数。以下是一个简化的雪花算法实现,用 Go 语言来实现雪花算法生成 ID。
package main
import (
"fmt"
"sync"
"time"
)
const (
// 起始时间戳(2021年1月1日的毫秒时间戳)
epoch int64 = 1609459200000
workerBits uint8 = 10 // 机器 ID 的位数
sequenceBits uint8 = 12 // 序列号的位数
workerMax int64 = -1 ^ (-1 << workerBits) // 最大机器 ID (1023)
sequenceMask int64 = -1 ^ (-1 << sequenceBits) // 最大序列号 (4095)
workerShift uint8 = sequenceBits // 机器 ID 的位移量
timestampShift uint8 = workerBits + workerShift // 时间戳的位移量
)
type Snowflake struct {
mu sync.Mutex
lastTimestamp int64
workerID int64
sequence int64
}
func NewSnowflake(workerID int64) (*Snowflake, error) {
if workerID < 0 || workerID > workerMax {
return nil, fmt.Errorf("worker ID should be between 0 and %d", workerMax)
}
return &Snowflake{
workerID: workerID,
}, nil
}
func (s *Snowflake) generateID() int64 {
s.mu.Lock()
defer s.mu.Unlock()
// 获取当前时间戳
timestamp := time.Now().UnixMilli() - epoch
if timestamp == s.lastTimestamp {
// 如果当前时间戳和上次生成 ID 的时间戳相同,递增序列号
s.sequence = (s.sequence + 1) & sequenceMask
if s.sequence == 0 {
// 如果序列号已经达到最大值,等待下一毫秒
for timestamp <= s.lastTimestamp {
timestamp = time.Now().UnixMilli() - epoch
}
}
} else {
// 不同时间戳,重置序列号
s.sequence = 0
}
s.lastTimestamp = timestamp
// 生成最终的 ID
id := (timestamp << timestampShift) |
(s.workerID << workerShift) |
s.sequence
return id
}
func main() {
sf, err := NewSnowflake(1) // 机器 ID 为 1
if err != nil {
fmt.Println("Error:", err)
return
}
for i := 0; i < 10; i++ {
id := sf.generateID()
fmt.Printf("Generated ID: %d\n", id)
}
}
雪花算法常用于以下几种场景:
总结来说,雪花算法通过巧妙的位操作,生成了一种分布式、高效且具有时间顺序的全局唯一 ID,非常适合在分布式系统中使用。