概观
- 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位 的合理限制。