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)
}
注意事项
-
xid依赖于系统时间、单调计数器,因此不是加密安全的。如果ID的不可预测性很重要,不应使用xid。
-
可以通过环境变量
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字节组成如下:
- 4字节时间戳(秒)
- 3字节机器标识
- 2字节进程ID
- 3字节随机数计数器
这种结构保证了:
- 同一进程内不会生成重复ID
- 不同进程在同一机器上几乎不会冲突
- 不同机器上冲突概率极低
性能比较
xid相比其他ID生成方案有以下优势:
- 比UUID更紧凑(12字节 vs 16字节)
- 比snowflake等方案更简单,不需要配置机器ID
- 比纯随机ID(如UUIDv4)更有序,利于数据库索引
注意事项
- xid不是加密安全的随机数,不适合安全敏感场景
- 如果需要在JavaScript中使用,建议先转换为字符串
- 机器标识基于主机名的哈希,容器环境中可能需要特别注意
xid是一个简单高效的分布式ID生成方案,适合大多数不需要严格单调递增的场景。