在现代分布式系统中,生成唯一 ID 是一个非常重要的环节,尤其在高并发、跨服务的场景下。
Go 语言中,有很多开源包和方法可以用来生成唯一 ID。
今天咱们就来深入探讨几种常见的生成唯一 ID 的方式,详细列举它们的特性、优点、缺点,以及适用场景。
1. 使用 google/uuid
包
什么是 UUID?
UUID(Universally Unique Identifier)是 128 位长的 ID,通过一定的算法生成,通常以 36 个字符的格式展示,如 "550e8400-e29b-41d4-a716-446655440000"。
UUID 非常适合分布式系统中需要生成全局唯一 ID 的场景。
使用示例
package main
import (
"fmt"
"github.com/google/uuid"
)
func main() {
id := uuid.New()
fmt.Println(id.String()) // 输出类似 "550e8400-e29b-41d4-a716-446655440000"
}
特性
唯一性:基于随机数和时间戳组合,生成全局唯一的 ID。
无序性:UUID 是随机生成的,不具有时间排序性。
性能:UUID 的生成速度较快,适合高并发环境。
优点
非常适合分布式系统中的全局唯一 ID 生成。
无需依赖中央节点,生成 ID 简单易用。
缺点
长度较长(36 个字符),不适合用于显示在 UI 上。
不具备时间排序特性。
适用场景
分布式环境中生成全局唯一 ID,例如用户 ID、订单 ID 等。
2. 使用 bwmarrin/snowflake
包
什么是雪花算法?
雪花算法(Snowflake)是 Twitter 开发的唯一 ID 生成算法。它生成 64 位的整型 ID,分为:1 位符号位、41 位时间戳、10 位机器 ID 和 12 位序列号。
这样可以保证在分布式环境中生成唯一的、有序的 ID。
使用示例
package main
import (
"fmt"
"github.com/bwmarrin/snowflake"
)
func main() {
node, _ := snowflake.NewNode(1)
id := node.Generate()
fmt.Println(id) // 输出类似 "1234567890123456789"
fmt.Println(id.Int64()) // 获取 int64 类型的 ID
}
特性
唯一性:由时间戳、机器 ID 和序列号组成,保证了全局唯一性。
排序性:ID 基于时间戳生成,具备时间排序特性。
性能:生成速度非常快,适用于高并发环境。
优点
ID 紧凑,适合用于数据库的主键或分布式系统的唯一 ID。
生成的 ID 有序,方便插入有序数据库。
缺点
需要配置机器节点 ID,部署时稍微复杂。
适用场景
分布式系统中需要有序的唯一 ID,如订单号、用户 ID 等。
3. 使用 oklog/ulid
包
什么是 ULID?
ULID(Universally Unique Lexicographically Sortable Identifier)是一种可排序的唯一 ID 生成方案。它的目标是提供一种比 UUID 更具可读性和排序性的唯一 ID。
使用示例
package main
import (
"fmt"
"github.com/oklog/ulid/v2"
"math/rand"
"time"
)
func main() {
entropy := ulid.Monotonic(rand.New(rand.NewSource(time.Now().UnixNano())), 0)
id := ulid.MustNew(ulid.Timestamp(time.Now()), entropy)
fmt.Println(id.String()) // 输出类似 "01FHZB1E8B9B8YZW6CVDBKMT6T"
}
特性
唯一性:基于时间戳和随机数的组合,保证全局唯一性。
排序性:ID 基于时间戳生成,具备排序特性。
可读性:使用 26 个字符的 Base32 编码,较 UUID 更紧凑。
优点
具备时间有序性,方便插入有序数据库。
紧凑且易读,适合展示和日志记录。
缺点
在极高并发场景下,存在理论上的碰撞可能。
适用场景
需要排序且唯一的 ID,如消息队列、日志 ID 等。
4. 使用 teris-io/shortid
包
什么是短 ID?
shortid
是一种用于生成简短、唯一 ID 的工具,适合需要短链或验证码的场景。生成的 ID 是 7-14 个字符,包含字母、数字、特殊字符。
使用示例
package main
import (
"fmt"
"github.com/teris-io/shortid"
)
func main() {
id, _ := shortid.Generate()
fmt.Println(id) // 输出类似 "dppUrjK3"
}
特性
唯一性:基于随机数生成,具有较高的唯一性。
无序性:生成的 ID 无时间排序特性。
可读性:短 ID 的长度适中,便于展示。
优点
生成的 ID 短小,适合在 UI 和用户交互中展示。
不依赖中央节点,适合单机使用。
缺点
不具备排序特性,不能用于需要时间顺序的场景。
适用场景
短链接、验证码、临时文件名等场景。
5. 使用 rs/xid
包
什么是 XID?
xid
是一种轻量级的全局唯一 ID 生成方案。长度为 20 个字符,包含 4 字节的 Unix 时间戳、5 字节的全局唯一机器 ID 和 3 字节的计数器。
使用示例
package main
import (
"fmt"
"github.com/rs/xid"
)
func main() {
id := xid.New()
fmt.Println(id.String()) // 输出类似 "9m4e2mr0ui3e8a215n4g"
}
特性
唯一性:通过时间戳、机器 ID 和计数器组合,保证全局唯一性。
排序性:ID 具备时间排序性,适合检索和排序。
性能:生成 ID 速度非常快。
适用场景
分布式系统中需要紧凑唯一 ID,如数据库主键、消息队列等。
6. 使用 segmentio/ksuid
包
什么是 KSUID?
ksuid
是一种可排序的唯一 ID,27 字节的 Base62 编码字符串,包含时间戳信息,方便时间排序。
使用示例
package main
import (
"fmt"
"github.com/segmentio/ksuid"
)
func main() {
id := ksuid.New()
fmt.Println(id.String()) // 输出类似 "1CHzCEl82ZZe2r2KS1qEz3XF8Ve"
}
特性
唯一性:基于时间戳、随机数生成,全局唯一。
排序性:具备时间排序特性,适合检索和排序。
可读性:27 字符的 Base62 字符串,适合展示和日志记录。
适用场景
需要唯一且具备时间排序特性的场景,如日志、消息队列等。
7. 使用 sony/sonyflake
包
什么是 Sonyflake?
sonyflake
是一种高效、分布式的唯一 ID 生成算法,生成的 ID 是 64 位整数,由时间戳、机器 ID 和序列号组成。
使用示例
package main
import (
"fmt"
"github.com/sony/sonyflake"
)
func main() {
sf := sonyflake.NewSonyflake(sonyflake.Settings{})
id, _ := sf.NextID()
fmt.Println(id) // 输出类似 "173301874793540608"
}
特性
唯一性:基于时间戳、机器 ID 和序列号,确保唯一性。
排序性:具备时间排序特性。
可扩展性:支持自定义机器 ID 位数和时间戳精度。
适用场景
高性能分布式环境,如订单号、日志序列。
最后
咱们使用表格总结一下 ~
方法 | 特性 | 有序性 | 长度 | 适用场景 |
---|---|---|---|---|
UUID | 全局唯一 | 无序 | 长(36) | 分布式环境、标识符 |
Snowflake | 全局唯一、排序 | 有序 | 中(64位) | 高性能分布式系统 |
ULID | 全局唯一、可排序 | 有序 | 中(26) | 日志、消息队列 |
XID | 全局唯一、时间排序 | 有序 | 中(20) | 分布式数据库主键 |
KSUID | 全局唯一、时间排序 | 有序 | 中(27) | 日志、消息队列 |
ShortID | 简短唯一 | 无序 | 短(7-14) | 短链接、验证码 |
Sonyflake | 高性能、全局唯一、排序 | 有序 | 中(64位) | 分布式系统 |
在选择唯一 ID 生成方式时,需要根据业务需求、系统架构、性能要求等方面综合考虑,合理选择合适的唯一 ID 生成策略,以保障系统的稳定和高效运行。
最后,谢谢你看到了这里👏 想要第一时间接收到推送,可以点个关注。
可点击下方👇 关注公众号
添加作者微信 👇 获取原创学习资料