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))
}

功能特点

  1. 支持生成64位和128位的ID
  2. 支持多种格式:
    • 整数格式
    • 十六进制字符串(base 16)
    • ASCII字符串(base 36)
  3. 支持自定义epoch时间(仅64位ID)
  4. 可以从生成的ID中提取时间戳信息

版本历史

当前版本:0.1.0

2019-01-03 - v0.1.0

首次发布功能:

  • 生成64位和128位ID
    • 支持格式:integerhex-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)
	}
}

设计考虑

  1. 线程安全:使用sync.Mutex确保并发安全
  2. 时钟回拨处理:检测到时钟回拨时返回错误
  3. 可配置性:允许自定义起始时间、工作机器ID等参数
  4. ID解析:提供方法解析生成的ID,便于调试和排查问题
  5. 性能优化:避免使用系统调用获取时间戳过于频繁

扩展功能

如果需要更强大的功能,可以考虑:

  1. 添加ZooKeeper/Etcd支持自动分配workerID
  2. 添加Redis缓存最近生成的ID,防止重启后短时间内生成重复ID
  3. 提供HTTP/gRPC接口作为服务
  4. 添加监控指标和日志记录

这个Olaf实现保持了Snowflake的核心优点,同时提供了简单易用的API,可以作为基础组件集成到各种分布式系统中。

回到顶部