概观
- WUID 是一个唯一的数字生成器,而不是 UUID 实现。
- WUID 比 UUID 快 10-135 倍,比使用 Redis 生成唯一数字快 4600 倍。
- WUID 按顺序生成唯一的 64 位整数。 高 28位 从数据存储加载。 到目前为止,支持 Redis、MySQL、PostgreSQL 和 MongoDB。
基准测试
BenchmarkWUID 100000000 10.3 ns/op 0 B/op 0 allocs/op BenchmarkRand 50000000 24.6 ns/op 0 B/op 0 allocs/op BenchmarkTimestamp 100000000 12.3 ns/op 0 B/op 0 allocs/op BenchmarkUUID_V1 20000000 107 ns/op 0 B/op 0 allocs/op BenchmarkUUID_V2 20000000 106 ns/op 0 B/op 0 allocs/op BenchmarkUUID_V3 5000000 359 ns/op 144 B/op 4 allocs/op BenchmarkUUID_V4 1000000 1376 ns/op 16 B/op 1 allocs/op BenchmarkUUID_V5 3000000 424 ns/op 176 B/op 4 allocs/op BenchmarkRedis 30000 46501 ns/op 176 B/op 5 allocs/op BenchmarkSnowflake 5000000 244 ns/op 0 B/op 0 allocs/op
特性
- 非常快
- 线程安全
- 跨越时间的独特性
- 在数据中心中是惟一的
- 如果所有数据中心共享相同的数据存储,或者使用不同的节id,则全局惟一
- 能够在一秒钟内生成1亿个唯一的数字
- 低 36位 即将用完时自动更新
安装
go get -u github.com/edwingeng/wuid
用法示例
Redis
import "github.com/edwingeng/wuid/redis/wuid"
newClient := func() (redis.Cmdable, bool, error) {
var client redis.Cmdable
// ...
return client, true, nil
}
// Setup
g := NewWUID("default", nil)
_ = g.LoadH28FromRedis(newClient, "wuid")
// Generate
for i := 0; i < 10; i++ {
fmt.Printf("%#016x\n", g.Next())
}
MySQL
import "github.com/edwingeng/wuid/mysql/wuid"
newDB := func() (*sql.DB, bool, error) {
var db *sql.DB
// ...
return db, true, nil
}
// Setup
g := NewWUID("default", nil)
_ = g.LoadH28FromMysql(newDB, "wuid")
// Generate
for i := 0; i < 10; i++ {
fmt.Printf("%#016x\n", g.Next())
}
MongoDB
import "github.com/edwingeng/wuid/mongo/wuid"
newClient := func() (*mongo.Client, bool, error) {
var client *mongo.Client
// ...
return client, true, nil
}
// Setup
g := NewWUID("default", nil)
_ = g.LoadH28FromMongo(newClient, "test", "wuid", "default")
// Generate
for i := 0; i < 10; i++ {
fmt.Printf("%#016x\n", g.Next())
}
Callback
import "github.com/edwingeng/wuid/callback/wuid"
// Setup
g := NewWUID("default", nil)
_ = g.LoadH28WithCallback(func() (uint64, func(), error) {
resp, err := http.Get("https://stackoverflow.com/")
if resp != nil {
defer func() {
_ = resp.Body.Close()
}()
}
if err != nil {
return 0, nil, err
}
bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return 0, nil, err
}
fmt.Printf("Page size: %d (%#06x)\n\n", len(bytes), len(bytes))
return uint64(len(bytes)), nil, nil
})
// Generate
for i := 0; i < 10; i++ {
fmt.Printf("%#016x\n", g.Next())
}
Mysql table creation
CREATE TABLE IF NOT EXISTS `wuid` (
`h` int(10) NOT NULL AUTO_INCREMENT,
`x` tinyint(4) NOT NULL DEFAULT '0',
PRIMARY KEY (`x`),
UNIQUE KEY `h` (`h`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
section ID(节 ID)
当您调用 wuid.NewWUID 时,可以使用 wuid.WithSection 为生成的数字指定自定义节 ID。 section ID 必须介于[1,15]之间。 它占据生成数字的最高4位。
最佳做法
- 使用不同的 keys/tables/docs 用于不同的目的。
- 将记录器(logger)传递给 wuid.NewWUID 并密切关注包含“续订失败”的警告,这意味着低36位将在几小时或几百小时内耗尽,并且 WUID 无法从数据存储中获取新编号。
- 使用 wuid.WithH28Verifier 给出高 28位 的合理限制。