golang高效生成带元数据的可排序唯一ID插件库sno的使用

Golang高效生成带元数据的可排序唯一ID插件库sno的使用

简介

sno是一个基于Snowflake设计的分布式系统唯一ID生成库,旨在对机器和人类友好、紧凑、多功能且快速。

sno logo

特性

  • 紧凑 - 二进制表示仅10字节,编码为16个字符
  • 可排序 - 支持按时间排序
  • 带时间戳 - 4毫秒分辨率,时间范围2010-2079年
  • 带元数据字节 - 可嵌入任意数据
  • 高性能 - 并发安全,无等待
  • 高吞吐 - 每秒可生成≥16,384,000个ID

安装

go get -u github.com/muyo/sno

基本使用

使用默认生成器生成ID非常简单:

id := sno.New(0) // 0是元数据字节

完整示例

package main

import (
	"fmt"
	"github.com/muyo/sno"
)

const (
	PersonType = iota
	OtherType
)

type Person struct {
	ID   sno.ID
	Name string
}

func main() {
	// 使用默认生成器
	id1 := sno.New(PersonType)
	fmt.Println("Default generator ID:", id1)
	
	// 创建自定义生成器
	generator, _ := sno.NewGenerator(&sno.GeneratorSnapshot{
		Partition: sno.Partition{'A', 10},
	}, nil)
	
	// 使用自定义生成器
	id2 := generator.New(OtherType)
	fmt.Println("Custom generator ID:", id2)
	
	// 创建带元数据的Person
	person := Person{
		ID:    sno.New(PersonType),
		Name: "张三",
	}
	fmt.Printf("Person: %+v\n", person)
}

生成器配置

可以创建自定义生成器并配置分区:

generator, err := sno.NewGenerator(&sno.GeneratorSnapshot{
	Partition: sno.Partition{'P', 0}, // 2字节分区
	SequenceMin: 0,      // 序列号最小值
	SequenceMax: 32767,  // 序列号最大值
}, nil)

元数据字节

元数据字节可以用于存储类型信息等:

const (
	UserType = 1
	OrderType = 2
)

// 生成用户ID
userID := sno.New(UserType)

// 生成订单ID 
orderID := sno.New(OrderType)

性能

sno在性能上表现优异,生成每个ID仅需约8.8纳秒。

与其他库对比

名称 二进制大小 编码大小 可排序 随机性 元数据 性能(ns/ID)
sno 10字节 16字符 8.8
UUID 16字节 36字符 ≥36.3
KSUID 20字节 27字符 206.0
ULID 16字节 26字符 ≥50.3
Snowflake 8字节 ≤20字符 28.9

总结

sno是一个高效、紧凑且功能丰富的唯一ID生成库,特别适合需要嵌入元数据并按时间排序的场景。其简单的API和出色的性能使其成为许多Go项目的理想选择。


更多关于golang高效生成带元数据的可排序唯一ID插件库sno的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang高效生成带元数据的可排序唯一ID插件库sno的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用sno生成带元数据的可排序唯一ID

sno是一个高效的Go库,用于生成可排序的、包含元数据的唯一ID(类似Twitter的Snowflake ID)。下面我将详细介绍sno的使用方法。

sno的特点

  1. 可排序性:ID按时间顺序生成,便于数据库索引
  2. 包含元数据:可嵌入分区、节点等信息
  3. 高效:无锁设计,性能优异
  4. 紧凑:使用Base32编码,比UUID更短

安装

go get github.com/muyo/sno

基本使用

package main

import (
	"fmt"
	"github.com/muyo/sno"
)

func main() {
	// 1. 创建一个生成器实例
	// 参数:节点ID (0-31)
	generator, err := sno.NewGenerator(1)
	if err != nil {
		panic(err)
	}

	// 2. 生成ID
	id := generator.New()

	fmt.Println("生成的ID:", id)
	fmt.Println("字符串表示:", id.String())
	fmt.Println("字节表示:", id.Bytes())
	fmt.Println("时间戳部分:", id.Time())
	fmt.Println("序列号部分:", id.Sequence())
}

带元数据的ID生成

sno允许在ID中嵌入1字节的元数据(0-255):

func main() {
	generator, _ := sno.NewGenerator(1)
	
	// 生成带元数据的ID
	idWithMeta := generator.NewWithMeta(42) // 42是元数据
	
	fmt.Println("带元数据的ID:", idWithMeta)
	fmt.Println("解析出的元数据:", idWithMeta.Meta())
}

性能基准

sno的性能非常高,以下是一个简单的基准测试:

func BenchmarkGenerate(b *testing.B) {
	generator, _ := sno.NewGenerator(1)
	b.ResetTimer()
	
	for i := 0; i < b.N; i++ {
		generator.New()
	}
}
/*
典型结果:
BenchmarkGenerate-8   	10000000	       120 ns/op
*/

实际应用示例

分布式系统中的应用

package main

import (
	"fmt"
	"github.com/muyo/sno"
)

const (
	MetaUser    = 1
	MetaProduct = 2
	MetaOrder   = 3
)

var (
	userGenerator    *sno.Generator
	productGenerator *sno.Generator
	orderGenerator   *sno.Generator
)

func init() {
	var err error
	userGenerator, err = sno.NewGenerator(1)
	if err != nil {
		panic(err)
	}
	productGenerator, err = sno.NewGenerator(2)
	if err != nil {
		panic(err)
	}
	orderGenerator, err = sno.NewGenerator(3)
	// 可以设置不同的节点ID来区分不同的服务实例
}

func NewUserID() sno.ID {
	return userGenerator.NewWithMeta(MetaUser)
}

func NewProductID() sno.ID {
	return productGenerator.NewWithMeta(MetaProduct)
}

func NewOrderID() sno.ID {
	return orderGenerator.NewWithMeta(MetaOrder)
}

func main() {
	userID := NewUserID()
	productID := NewProductID()
	orderID := NewOrderID()

	fmt.Printf("User ID: %s (meta: %d)\n", userID, userID.Meta())
	fmt.Printf("Product ID: %s (meta: %d)\n", productID, productID.Meta())
	fmt.Printf("Order ID: %s (meta: %d)\n", orderID, orderID.Meta())
}

数据库主键示例

package main

import (
	"database/sql"
	"fmt"
	"github.com/muyo/sno"
	_ "github.com/lib/pq"
)

type User struct {
	ID      sno.ID
	Name    string
	Email   string
}

func main() {
	db, err := sql.Open("postgres", "user=postgres dbname=test sslmode=disable")
	if err != nil {
		panic(err)
	}
	defer db.Close()

	generator, _ := sno.NewGenerator(1)
	
	// 创建用户
	user := User{
		ID:    generator.NewWithMeta(1), // 1表示用户类型
		Name:  "John Doe",
		Email: "john@example.com",
	}

	_, err = db.Exec("INSERT INTO users (id, name, email) VALUES ($1, $2, $3)",
		user.ID, user.Name, user.Email)
	if err != nil {
		panic(err)
	}

	// 查询用户
	var fetchedUser User
	err = db.QueryRow("SELECT id, name, email FROM users WHERE id = $1", user.ID).
		Scan(&fetchedUser.ID, &fetchedUser.Name, &fetchedUser.Email)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Fetched user: %+v\n", fetchedUser)
}

注意事项

  1. 节点ID范围是0-31,确保在分布式系统中每个节点有唯一ID
  2. 时间戳部分使用41位,大约可以使用69年
  3. 序列号12位,每毫秒可生成4096个ID
  4. 默认使用Base32编码,输出字符串长度为20个字符

sno是一个简单但功能强大的ID生成库,特别适合需要可排序ID和嵌入元数据的场景。它的性能优异,适合高并发环境使用。

回到顶部