目前知名且好用的短整数 ID 生成器是 Yitter 的 IdGenerator。相对于其他雪花类算法库,IdGenerator 最大的优点就是不固定长度,可按需配置各个段的值或者偏移,大幅减少了 ID 的长度,避免了号段浪费。如果并发量上来了,可以直接更改配置实现无缝升级。
IdGenerator 改进明显,但是对于本人手上的小项目来说 ID 还是太长了(默认配置下随手甩出来的 ID 就是上万亿的数),也用不着这么高的并发(别说一秒 5W 个 id ,一天能有 5W 个订单都能让人笑醒)。此外全局只能一个生成器,不能根据业务场景采用不同的生成器:购买订单和退货订单 ID 是可以重复的,并且一般情况下退货订单数量比购买订单少一个量级,可以采用更短的 ID 。
出于上面的考虑,本人对 IdGenerator 库进行了如下改进:
支持不同的时间精度。原版中默认是 1 毫秒,现在新增了 10 毫秒 – 10 秒(实际上是 8 毫秒、128 毫秒、1024 毫秒 和 8192 毫秒,方便用位运算代替整数除法)的精度选项。低精度选项(例如 1 秒、10 秒)适合并发量小的项目(例如 1 秒内最多 30 个订单),能大大减少 ID 的长度;
WorkIdBitLength
支持为 0 ,让单机应用能生成更短或数值更小的 ID ;
支持不同场景使用不同的 Id 生成器,同时兼容原来的接口:
// 兼容原版使用方式
var options = new IdGeneratorOptions();
YitIdHelper.setIdGenerator(options);
var newId = YitIdHelper.nextId();
// 退款订单场景
final var REFUND = "refund";
var options2 = new IdGeneratorOptions();
// 退款相当于购买订单频率更低,可以降低时间精度要求
options2.Precision=1;
YitIdHelper.setIdGenerator(REFUND, options2);
var newId = YitIdHelper.nextId(REFUND);
本人测试了不同算法和时间精度下生成的 ID ,结果为:
# 调用 Hutool 的 IdUtil.getSnowflakeNextId() 方法生成
这是用方法 snowflake 生成的 Id: 1957067304089067520 (长度 19 位)
=====================================
# 使用 IdGenerator 的默认配置,无任何改动
这是用方法 默认 生成的 Id: 80881995821061 (长度 14 位)
=====================================
# 修改 options.Precision = 1
这是用方法 precision1 生成的 Id:10110249734149 (长度 14 位)
=====================================
# 修改 options.Precision = 2
这是用方法 precision2 生成的 Id:631890624517 (长度 12 位)
=====================================
# 修改 options.Precision = 3
这是用方法 precision3 生成的 Id:78986326021 (长度 11 位)
=====================================
# 修改 options.Precision = 4
这是用方法 precision4 生成的 Id:9873293317 (长度 10 位)
对于本人手上的小项目,没有多大的并发( 1 天大概几百个订单),可以配置生成更短的 ID:
var options = new IdGeneratorOptions();
options.Precision = 4; // 时间精度为 10 秒(实际上是 8 秒)
options.WorkerIdBitLength = 1; // 最多两个应用实例
options.SeqBitLength = 6; // 每 10 秒可以生成 29 个订单,高峰期超过也没关系,会自动进行时间漂移
YitIdHelper.setIdGenerator("order", options);
var id = YitIdHelper.nextId("order");
# 生成的 ID:2707882245
此配置下订单号为 10 位,这个长度是非常能接受的,并且值也很小。
Java 版本的改进代码已经放到 Github ,其他语言版本本人暂时用不着,因为未更改。如果有需要按照 Java 版本的方式更改即可,代码量其实很少。另外目前没有 Maven 包,使用时需要将代码下载下来直接使用。
![]() |
1
maokg 15 天前
改进->改退(开玩笑,适合自己场景的库才是最好的
|
![]() |
2
xhawk 15 天前 via Android
前几天看了一下,如果订单是跟数据库做一个绑定的话,那这个订单号其实逻辑上就可以设计的很短。意思就是说,我们先做一个简单的假设,一个数据库可以存放 1 亿的订单,经过这样子分库之后,那么这个订单就可以无限地变大了
|
![]() |
5
netnr 15 天前
一直在用 53 位的雪花 ID ,兼容前端 JS Number.MAX_SAFE_INTEGER ,单机版
Timestamp 41 位的时间戳,约 69 年 Sequence 12 位的序列号,4096/ms |
7
clarkethan 14 天前
追求很短的 id ,建议全局递增即可
另外,同一个系统内的购买订单和退货订单,如果可能,id 还是尽量别重复为好,毕竟 id 是一个还算充足的的资源 |
![]() |
8
tlanyan OP @clarkethan 就是不想要递增 id 才用这类 id 算法,另外这里说的可以重复只是一个避免心智负担的要求,这类 id 生成算法基本上就不太可能生成重复 id
|
9
LoNeZ 12 天前
...不都是 4 字节 8 字节吗...为什么会嫌长?
|
![]() |
10
tlanyan OP 8 个字节字符串最大将近 20 位,那是非常长
|