ULID规范解读与实现原理( 二 )


规范的表示形式ULID规范的字符串表示形式如下:
ttttttttttrrrrrrrrrrrrrrrrwheret is Timestamp (10 characters)r is Randomness (16 characters)也就是:

  • 时间戳占据高(左边)10个(编码后的)字符
  • 随机数占据低(右边)16个(编码后的)字符
ULID规范的字符串表示形式的长度是确定的 , 共占据26个字符 。
编码使用Crockford Base32编码算法 , 这个编码算法的字母表如下:
0123456789ABCDEFGHJKMNPQRSTVWXYZ该字母表排除了ILOU字母 , 目的是避免混淆和滥用 。此算法实现不难 , 它的官网有详细的算法说明(见https://www.crockford.com/base32.html):
ULID规范解读与实现原理

文章插图
单调性(如果启用了单调性这个特性为前提下)当在相同的毫秒内生成多个ULID时 , 可以保证排序的顺序 。也就是说 , 如果检测到相同的毫秒 , 则随机分量在最低有效位上加1位(带进位) 。例如:
monotonicUlid()// 01BX5ZZKBKACTAV9WEVGEMMVRZmonotonicUlid()// 01BX5ZZKBKACTAV9WEVGEMMVS0溢出错误处理从技术实现上来看 , 26个字符的Base32编码字符串可以包含130 bit信息 , 而ULID只包含128 bit信息 , 所以该编码算法是能完全满足ULID的需要 。基于Base32编码能够生成的最大的合法ULID其实就是7ZZZZZZZZZZZZZZZZZZZZZZZZZ , 并且使用的时间戳为epoch time281474976710655或者说2 ^ 48 - 1 。对于任何对大于此值的ULID进行解码或编码的尝试都应该被所有实现拒绝 , 以防止溢出错误 。
二进制布局二进制布局的多个部分被编码为16 byte , 每个部分都以最高字节优先(网络字节序 , 也就是big-endian)进行编码 , 布局如下:
0123 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|32_bit_uint_time_high|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|16_bit_uint_time_low|16_bit_uint_random|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|32_bit_uint_random|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|32_bit_uint_random|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ULID使用对于script标签引用:
<script src="http://shimg.jingyanzongjie.com/230726/02311632Q-2.jpg"></script><script>ULID.ulid()</script>NPM安装:
npm install --save ulidTypeScript, ES6+, Babel, Webpack, Rollup等等下使用:
// importimport { ulid } from 'ulid'ulid()// CommonJS envconst ULID = require('ulid')ULID.ulid()后端Maven项目中使用需要引入依赖 , 这里选用ulid-creator实现:
<dependency><groupId>com.github.f4b6a3</groupId><artifactId>ulid-creator</artifactId><version>5.0.2</version></dependency>然后调用UlidCreator#getUlid()系列方法:
// 常规Ulid ulid = UlidCreator.getUlid();// 单调排序Ulid ulid = UlidCreator.getMonotonicUlid();实现ULID前面已经提到ULID的规范 , 其实具体实现ULID

经验总结扩展阅读