shortid 是一个面向生产的 Go ID 生成 SDK。
它兼容雪花算法思路,但把“机器ID分配”升级为租约模型,更适合云原生弹性场景。
传统雪花的核心风险是 machine_id 管理:固定配置或人工分配在容器/Serverless下容易冲突。
shortid 的迁移目标:
- 保留雪花的核心优点:
uint64、高吞吐、按时间趋势递增。 - 将机器号管理升级为租约(可接 Redis / etcd / 第三方)。
- 业务接入保持简单:本地单机和分布式都走统一 API。
| 雪花概念 | shortid 对应 | 迁移方式 |
|---|---|---|
固定 machine_id |
New(machineID, businessType) |
单机/固定节点可直接迁 |
| 机器号中心分配 | MachineIDLeaseProvider |
推荐,替代人工机器号 |
| 序列号 | 本地序列或 SequenceProvider |
默认本地,强一致再上远端 |
生成 int64 |
NextID(ctx) -> uint64 |
大多数场景直接替换 |
最短迁移示例:
g, err := shortid.New(1, shortid.BusinessOrder)
if err != nil {
panic(err)
}
id, err := g.NextID(context.Background())flowchart LR
A["业务代码<br/>(HTTP/gRPC/MQ/Job)"] --> B["Endpoint(可选)"]
A --> C["Generator(核心发号)"]
B --> C
C --> D["MachineIDLeaseProvider<br/>(Redis/etcd/第三方)"]
C --> E["SequenceProvider(可选)"]
D --> F["Lease Store"]
E --> G["Sequence Store"]
设计原则:
- 核心发号与传输层解耦(HTTP/gRPC/MQ 共享一套发号逻辑)。
- 机器ID通过租约保证“持有者身份”和“自动过期”。
- 适配层可插拔:Redis/etcd/第三方都可实现接口接入。
MachineIDLeaseProvider 要求:
Acquire:原子抢占机器ID租约。Renew:必须 token CAS(只有持有者能续租)。Release:必须 token CAS(只有持有者能释放)。- 失租后必须停止发号(返回错误)。
详细设计见 docs/MACHINE_ID_LEASE.md。
- 单实例:固定
MachineID,本地序列(最低延迟)。 - 弹性实例:
MachineIDLeaseProvider+ 本地序列(推荐)。 - 跨实例强一致序列:再接
SequenceProvider(吞吐换一致性)。
Acquire使用 单次 Lua 在 Redis 侧完成“游标推进 + 槽位抢占”。Renew/Release使用 token CAS,保证安全。Slots可配置(默认64),便于按业务规模调优。
测试命令:
go test -run 'TestPerf_RedisLeaseMode_(SingleInstance|TwoInstances|MultiInstances)$' -v ./...测试环境(真实本机实测):
- 时间:2026-03-08(最新实测)
- 机器:MacBook Pro (MacBookPro18,3)
- CPU:Apple M1 Pro,8 Core (6P + 2E)
- 内存:16 GB
- 系统:macOS 15.6 (Darwin 24.6.0, arm64)
- Redis:本地 Docker 单实例(
localhost:6379) - 模式:
MachineIDLeaseProvider(Lua Acquire)+ 本地序列号
| 场景 | 请求量 | 总耗时 | 平均耗时 | QPS |
|---|---|---|---|---|
| 单实例(1个Generator) | 50,000 | 4.281s | 85.629µs | 11,678 |
| 双实例(2个Generator并发) | 60,000 | 2.597s | 43.280µs | 23,105 |
| 16实例并发 | 80,000 | 0.431s | 5.383µs | 185,748 |
| 32实例并发 | 96,000 | 0.268s | 2.788µs | 358,606 |
| 64实例并发 | 96,000 | 0.126s | 1.315µs | 759,904 |
说明:
- 上述数据来自当前机器实测日志(
go test -v输出),非理论估算。 - 16/32/64 场景主要反映“并行扩展能力”,不等同于线上端到端吞吐。
- 线上请按目标实例规格、网络与Redis拓扑复测。
为什么单实例 50,000 条要约 4 秒,而 64 实例快很多:
- 单实例存在算法上限:当前位宽下,单 machineID 每 10ms 最多 128 个序列,即约
12,800 QPS。 - 实测单实例
11,678 QPS已接近该上限,所以50,000 / 11,678 ≈ 4.28s,属于正常结果。 - 64 实例并发是横向扩展,总上限约
12,800 * 64 = 819,200 QPS;实测759,904 QPS,接近总上限。 - 因此“64 实例更快”本质是并行放大总吞吐,不是单实例退化。
shortid 的时间粒度为 10ms,序列位宽 7 bit:
- 单 machineID 上限:
128 / 10ms = 12,800 QPS - 64 machineID 槽位总上限:
12,800 * 64 = 819,200 QPS
本机最新实测峰值(64实例)为 759,904 QPS,约等于理论上限的 92.8%。
按 QPS * 86,400 估算每日可生成短链数:
| 场景 | QPS | 预估每日可生成短链 |
|---|---|---|
| 单实例 | 11,678 | 1,008,979,200(约 10.09 亿) |
| 双实例 | 23,105 | 1,996,272,000(约 19.96 亿) |
| 64实例(本机实测) | 759,904 | 65,655,705,600(约 656.56 亿) |
| 64实例(理论上限) | 819,200 | 70,778,880,000(约 707.79 亿) |
注意:
- 这是“ID生成层”的容量,不包含数据库写入、缓存命中、重定向服务与网络开销。
- 真正短链系统总吞吐通常由存储层与读写链路先到瓶颈。
- 超过单集群 64 槽位时,建议按业务分片/租户分片做多集群扩展。
安装:
go get github.com/gostool/shortid基础验证:
go test ./...
SHORTID_REQUIRE_REDIS_TESTS=1 go test ./...
go test -race ./...- docs/INTEGRATION_QUICKSTART.md
- docs/API_CONTRACT.md
- docs/UPGRADING.md
- docs/RELEASE_POLICY.md
- docs/MACHINE_ID_LEASE.md
- 本项目采用 MIT License。
- 版权归属:
Copyright (c) 2024-2026 Huo Yinghui - 使用、修改、分发和商用均允许;但分发时必须保留版权声明与许可文本。