golang实现Twitter Snowflake分布式ID生成插件库olaf的使用
Golang实现Twitter Snowflake分布式ID生成插件库Olaf的使用
Olaf是一个Golang实现的Twitter Snowflake分布式ID生成器,它能够生成64位和128位的唯一ID。
安装
go get github.com/btnguyen2k/olaf
使用示例
下面是一个完整的示例代码,展示如何使用Olaf生成不同类型的ID:
package main
import (
"fmt"
"github.com/btnguyen2k/olaf"
)
func main() {
// 使用默认epoch时间
o := olaf.NewOlaf(1981) // 1981是worker ID
// 也可以使用自定义epoch时间(注意:epoch时间单位是毫秒)
// o := olaf.NewOlafWithEpoch(103, 1546543604123)
// 生成64位ID
id64 := o.Id64()
id64Hex := o.Id64Hex()
id64Ascii := o.Id64Ascii()
fmt.Println("ID 64-bit (int) : ", id64, " / Timestamp: ", o.ExtractTime64(id64))
fmt.Println("ID 64-bit (hex) : ", id64Hex, " / Timestamp: ", o.ExtractTime64Hex(id64Hex))
fmt.Println("ID 64-bit (ascii) : ", id64Ascii, " / Timestamp: ", o.ExtractTime64Ascii(id64Ascii))
// 生成128位ID
id128 := o.Id128()
id128Hex := o.Id128Hex()
id128Ascii := o.Id128Ascii()
fmt.Println("ID 128-bit (int) : ", id128.String(), " / Timestamp: ", o.ExtractTime128(id128))
fmt.Println("ID 128-bit (hex) : ", id128Hex, " / Timestamp: ", o.ExtractTime128Hex(id128Hex))
fmt.Println("ID 128-bit (ascii): ", id128Ascii, " / Timestamp: ", o.ExtractTime128Ascii(id128Ascii))
}
功能特点
- 支持生成64位和128位的ID
- 支持多种格式:
- 整数格式
- 十六进制字符串(base 16)
- ASCII字符串(base 36)
- 支持自定义epoch时间(仅64位ID)
- 可以从生成的ID中提取时间戳信息
版本历史
当前版本:0.1.0
2019-01-03 - v0.1.0
首次发布功能:
- 生成64位和128位ID
- 支持格式:
integer
、hex-string
(base 16)和ascii-string
(base 36) - 支持自定义epoch(仅64位ID)
- 支持格式:
- 可以从生成的ID中提取时间元数据
注意:自2019年4月10日起,Olaf已作为子模块合并到btnguyen2k/consu项目中。
更多关于golang实现Twitter Snowflake分布式ID生成插件库olaf的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang实现Twitter Snowflake分布式ID生成插件库olaf的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用Golang实现Twitter Snowflake分布式ID生成插件库Olaf
Snowflake是Twitter开源的分布式ID生成算法,它生成的ID具有全局唯一、趋势递增、高性能等特点。下面我将介绍如何使用Golang实现一个名为"Olaf"的Snowflake分布式ID生成插件库。
Snowflake算法原理
Snowflake的ID结构如下:
- 1位符号位(始终为0)
- 41位时间戳(毫秒级,约69年)
- 10位工作机器ID(5位数据中心ID + 5位机器ID)
- 12位序列号(每毫秒可生成4096个ID)
Olaf实现代码
package olaf
import (
"errors"
"sync"
"time"
)
const (
epoch int64 = 1609459200000 // 自定义起始时间(2021-01-01 00:00:00 UTC)
workerIDBits uint8 = 5 // 机器ID位数
dataCenterBits uint8 = 5 // 数据中心ID位数
sequenceBits uint8 = 12 // 序列号位数
maxWorkerID int64 = -1 ^ (-1 << workerIDBits) // 最大机器ID
maxDataCenterID int64 = -1 ^ (-1 << dataCenterBits) // 最大数据中心ID
maxSequence int64 = -1 ^ (-1 << sequenceBits) // 最大序列号
timeShift = workerIDBits + dataCenterBits + sequenceBits
dataCenterShift = workerIDBits + sequenceBits
workerShift = sequenceBits
)
// Olaf Snowflake ID生成器
type Olaf struct {
mu sync.Mutex
lastTimestamp int64
workerID int64
dataCenterID int64
sequence int64
}
// NewOlaf 创建一个新的Olaf实例
func NewOlaf(workerID, dataCenterID int64) (*Olaf, error) {
if workerID < 0 || workerID > maxWorkerID {
return nil, errors.New("worker ID out of range")
}
if dataCenterID < 0 || dataCenterID > maxDataCenterID {
return nil, errors.New("data center ID out of range")
}
return &Olaf{
lastTimestamp: 0,
workerID: workerID,
dataCenterID: dataCenterID,
sequence: 0,
}, nil
}
// NextID 生成下一个ID
func (o *Olaf) NextID() (int64, error) {
o.mu.Lock()
defer o.mu.Unlock()
timestamp := time.Now().UnixNano() / 1e6 // 毫秒时间戳
if timestamp < o.lastTimestamp {
return 0, errors.New("clock moved backwards")
}
if o.lastTimestamp == timestamp {
o.sequence = (o.sequence + 1) & maxSequence
if o.sequence == 0 {
// 当前毫秒序列号用完,等待下一毫秒
timestamp = o.waitNextMillis(timestamp)
}
} else {
o.sequence = 0
}
o.lastTimestamp = timestamp
// 组合各部分生成ID
id := ((timestamp - epoch) << timeShift) |
(o.dataCenterID << dataCenterShift) |
(o.workerID << workerShift) |
o.sequence
return id, nil
}
// waitNextMillis 等待下一毫秒
func (o *Olaf) waitNextMillis(lastTimestamp int64) int64 {
timestamp := time.Now().UnixNano() / 1e6
for timestamp <= lastTimestamp {
time.Sleep(100 * time.Microsecond)
timestamp = time.Now().UnixNano() / 1e6
}
return timestamp
}
// ParseID 解析ID
func (o *Olaf) ParseID(id int64) (timestamp, dataCenterID, workerID, sequence int64) {
timestamp = (id >> timeShift) + epoch
dataCenterID = (id >> dataCenterShift) & maxDataCenterID
workerID = (id >> workerShift) & maxWorkerID
sequence = id & maxSequence
return
}
使用示例
package main
import (
"fmt"
"olaf"
)
func main() {
// 创建一个新的Olaf实例,workerID=1, dataCenterID=1
generator, err := olaf.NewOlaf(1, 1)
if err != nil {
panic(err)
}
// 生成10个ID
for i := 0; i < 10; i++ {
id, err := generator.NextID()
if err != nil {
fmt.Printf("Error generating ID: %v\n", err)
continue
}
fmt.Printf("Generated ID: %d\n", id)
// 解析ID
timestamp, dataCenterID, workerID, sequence := generator.ParseID(id)
fmt.Printf("Parsed ID - Timestamp: %d, DataCenterID: %d, WorkerID: %d, Sequence: %d\n",
timestamp, dataCenterID, workerID, sequence)
}
}
设计考虑
- 线程安全:使用sync.Mutex确保并发安全
- 时钟回拨处理:检测到时钟回拨时返回错误
- 可配置性:允许自定义起始时间、工作机器ID等参数
- ID解析:提供方法解析生成的ID,便于调试和排查问题
- 性能优化:避免使用系统调用获取时间戳过于频繁
扩展功能
如果需要更强大的功能,可以考虑:
- 添加ZooKeeper/Etcd支持自动分配workerID
- 添加Redis缓存最近生成的ID,防止重启后短时间内生成重复ID
- 提供HTTP/gRPC接口作为服务
- 添加监控指标和日志记录
这个Olaf实现保持了Snowflake的核心优点,同时提供了简单易用的API,可以作为基础组件集成到各种分布式系统中。