golang全局唯一ID生成插件库xid的使用

Golang全局唯一ID生成插件库xid的使用

简介

xid是一个全局唯一ID生成器库,可以直接安全地在服务器代码中使用。它使用Mongo Object ID算法生成全局唯一ID,但采用了不同的序列化方式(base32hex)使其在字符串传输时更短。

xid的ID组成:

  • 4字节表示自Unix纪元以来的秒数
  • 3字节机器标识符
  • 2字节进程ID
  • 3字节计数器,从随机值开始

特性

  • 大小:12字节(96位),比UUID小,比Snowflake大
  • 默认使用Base32 hex编码(作为可打印字符串传输时为20个字符,仍可排序)
  • 无需配置,不需要设置唯一的机器和/或数据中心ID(如果需要可以配置)
  • K-ordered
  • 嵌入式时间,精度为1秒
  • 每台主机/进程每秒保证16,777,216(24位)个唯一ID的唯一性
  • 无锁(即:与UUIDv1和v2不同)

安装

go get github.com/rs/xid

使用示例

基本用法

package main

import (
	"fmt"
	"github.com/rs/xid"
)

func main() {
	// 生成一个新的xid
	guid := xid.New()

	// 打印字符串形式的xid
	fmt.Println(guid.String())
	// 输出示例: 9m4e2mr0ui3e8a215n4g
}

获取xid的嵌入信息

package main

import (
	"fmt"
	"github.com/rs/xid"
	"time"
)

func main() {
	guid := xid.New()

	// 获取机器标识符
	machine := guid.Machine()
	fmt.Printf("Machine: %v\n", machine)

	// 获取进程ID
	pid := guid.Pid()
	fmt.Printf("PID: %v\n", pid)

	// 获取生成时间
	t := guid.Time()
	fmt.Printf("Time: %v\n", t.Format(time.RFC3339))

	// 获取计数器值
	counter := guid.Counter()
	fmt.Printf("Counter: %v\n", counter)
}

注意事项

  1. xid依赖于系统时间、单调计数器,因此不是加密安全的。如果ID的不可预测性很重要,不应使用xid。

  2. 可以通过环境变量XID_MACHINE_ID设置MachineID,以允许对生成进行微调控制。

性能对比

xid与Go的UUID库性能对比:

BenchmarkXID        	20000000	        91.1 ns/op	      32 B/op	       1 allocs/op
BenchmarkXID-2      	20000000	        55.9 ns/op	      32 B/op	       1 allocs/op
BenchmarkXID-4      	50000000	        32.3 ns/op	      32 B/op	       1 allocs/op
BenchmarkUUIDv1     	10000000	       204 ns/op	      48 B/op	       1 allocs/op
BenchmarkUUIDv1-2   	10000000	       160 ns/op	      48 B/op	       1 allocs/op
BenchmarkUUIDv1-4   	10000000	       195 ns/op	      48 B/op	       1 allocs/op
BenchmarkUUIDv4     	 1000000	      1503 ns/op	      64 B/op	       2 allocs/op
BenchmarkUUIDv4-2   	 1000000	      1427 ns/op	      64 B/op	       2 allocs/op
BenchmarkUUIDv4-4   	 1000000	      1452 ns/op	      64 B/op	       2 allocs/op

注意:UUIDv1需要一个全局锁,因此随着我们添加更多CPU,性能会下降。


更多关于golang全局唯一ID生成插件库xid的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang全局唯一ID生成插件库xid的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang全局唯一ID生成库xid使用指南

xid是一个轻量级的分布式唯一ID生成器,专为Golang设计。它生成的ID具有以下特点:

  • 分布式安全:无需协调即可生成唯一ID
  • 时间有序:可以按生成时间排序
  • 紧凑:只有12字节,比UUID(16字节)更小
  • 基础类型:使用[12]byte数组存储,易于存储和传输

安装xid

go get github.com/rs/xid

基本使用

package main

import (
	"fmt"
	"github.com/rs/xid"
)

func main() {
	// 生成一个新的xid
	id := xid.New()
	
	fmt.Println("生成的ID:", id)
	fmt.Println("字符串形式:", id.String())
	fmt.Println("十六进制:", id.Machine(), id.Pid(), id.Time(), id.Counter())
	fmt.Println("时间部分:", id.Time())
	fmt.Println("机器标识:", id.Machine())
	fmt.Println("进程ID:", id.Pid())
	fmt.Println("计数器:", id.Counter())
}

解析已有的xid

func parseXID() {
	// 从字符串解析xid
	idFromString, err := xid.FromString("b50vl5e54p6sbpf630k0")
	if err != nil {
		panic(err)
	}
	fmt.Println("从字符串解析:", idFromString)
	
	// 从字节数组解析
	bytes := []byte{0x4d, 0x88, 0xe1, 0x5b, 0x60, 0xf4, 0x86, 0xe4, 0x28, 0x41, 0x2d, 0xc9}
	idFromBytes := xid.ID(bytes)
	fmt.Println("从字节解析:", idFromBytes)
}

在Web应用中使用

package main

import (
	"encoding/json"
	"net/http"
	"github.com/rs/xid"
)

type User struct {
	ID   xid.ID `json:"id"`
	Name string `json:"name"`
}

func createUserHandler(w http.ResponseWriter, r *http.Request) {
	user := User{
		ID:   xid.New(),
		Name: "John Doe",
	}
	
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(user)
}

func main() {
	http.HandleFunc("/users", createUserHandler)
	http.ListenAndServe(":8080", nil)
}

在数据库中使用

xid可以很方便地作为数据库主键:

package main

import (
	"database/sql"
	"fmt"
	_ "github.com/lib/pq"
	"github.com/rs/xid"
)

type Product struct {
	ID    xid.ID
	Name  string
	Price float64
}

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

	// 创建表
	_, err = db.Exec(`CREATE TABLE IF NOT EXISTS products (
		id BYTEA PRIMARY KEY,
		name TEXT,
		price NUMERIC
	)`)
	if err != nil {
		panic(err)
	}

	// 插入数据
	product := Product{
		ID:    xid.New(),
		Name:  "Laptop",
		Price: 999.99,
	}
	
	_, err = db.Exec("INSERT INTO products (id, name, price) VALUES ($1, $2, $3)",
		product.ID, product.Name, product.Price)
	if err != nil {
		panic(err)
	}

	// 查询数据
	rows, err := db.Query("SELECT id, name, price FROM products")
	if err != nil {
		panic(err)
	}
	defer rows.Close()

	for rows.Next() {
		var p Product
		err = rows.Scan(&p.ID, &p.Name, &p.Price)
		if err != nil {
			panic(err)
		}
		fmt.Printf("%+v\n", p)
	}
}

xid的结构

xid的12字节组成如下:

  1. 4字节时间戳(秒)
  2. 3字节机器标识
  3. 2字节进程ID
  4. 3字节随机数计数器

这种结构保证了:

  • 同一进程内不会生成重复ID
  • 不同进程在同一机器上几乎不会冲突
  • 不同机器上冲突概率极低

性能比较

xid相比其他ID生成方案有以下优势:

  • 比UUID更紧凑(12字节 vs 16字节)
  • 比snowflake等方案更简单,不需要配置机器ID
  • 比纯随机ID(如UUIDv4)更有序,利于数据库索引

注意事项

  1. xid不是加密安全的随机数,不适合安全敏感场景
  2. 如果需要在JavaScript中使用,建议先转换为字符串
  3. 机器标识基于主机名的哈希,容器环境中可能需要特别注意

xid是一个简单高效的分布式ID生成方案,适合大多数不需要严格单调递增的场景。

回到顶部