目前知名且好用的短整数 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 54 天前 改进->改退(开玩笑,适合自己场景的库才是最好的 |
![]() | 2 xhawk 54 天前 via Android 前几天看了一下,如果订单是跟数据库做一个绑定的话,那这个订单号其实逻辑上就可以设计的很短。意思就是说,我们先做一个简单的假设,一个数据库可以存放 1 亿的订单,经过这样子分库之后,那么这个订单就可以无限地变大了 |
![]() | 5 netnr   54 天前 一直在用 53 位的雪花 ID ,兼容前端 JS Number.MAX_SAFE_INTEGER ,单机版 Timestamp 41 位的时间戳,约 69 年 Sequence 12 位的序列号,4096/ms |
7 clarkethan 53 天前 追求很短的 id ,建议全局递增即可 另外,同一个系统内的购买订单和退货订单,如果可能,id 还是尽量别重复为好,毕竟 id 是一个还算充足的的资源 |
![]() | 8 tlanyan OP @clarkethan 就是不想要递增 id 才用这类 id 算法,另外这里说的可以重复只是一个避免心智负担的要求,这类 id 生成算法基本上就不太可能生成重复 id |
9 LoNeZ 51 天前 ...不都是 4 字节 8 字节吗...为什么会嫌长? |
![]() | 10 tlanyan OP 8 个字节字符串最大将近 20 位,那是非常长 |