snowflakeid-ro

Twitter Snowflake ID generator

Usage no npm install needed!

<script type="module">
  import snowflakeidRo from 'https://cdn.skypack.dev/snowflakeid-ro';
</script>

README

Snowflake id 生成器

  • 2017-03-14 1.0.4 增加human readable格式转换支持, toHumanReadable(), fromHumanReadable()

关于Snowflake id

基本思想源于twitter的Snowflake方案,该实现可提供高性能、低延迟、高可用的ID生成。

每个ID是一个long类型的整数,结构如下:

0     A     41    B     51    C   54  D  63
+-----------+-----------+---------+--------+
| timestamp |   hw id   | shardId | seq Id |
+-----------+-----------+---------+--------+
  • A. 前41位是timestamp,精确到千分之一秒,即mS。这样可以使ID生成变得有序。
  • B. 10位HW ID(表示主机或者docker),这样可以有1024个节点, HwID由MAC地址最后7位+本实例进程号最后3位组成。
  • C. 3位分片id, 最大支持8个分片
  • D. 最后10位为了解决并发冲突问题,并发请求时以此10位作累加,这样在同一个毫秒最多可以生成1024个ID。

通过以上方案,可以快速生成时间有序的,带节点标识的ID。基于这个思想,我们可以做各种变形以满足自身需要,比如可以调整四部分的顺序和每一部分的位数以满足具体场景;可以开启多个进程,每个进程负责某些node节点的ID生成以避免单点;可以精简位数,并做编码转换以减少ID长度等等。

设计思路

这个方案与其它snowflake id生成器不同的地方有:

  1. 直接使用第0位,不再留空。所以需要在DB Schema中定义存储的字段为BIGINT UNSIGNED
CREATE TABLE test(
    id    BIGINT UNSIGNED,
);
  1. 采用了3位shardId,用以数据表分片扩展用途。
  2. 10位HwID用以标识各主机或者容器(MAC最后7位+进程ID后3位)
  3. 采用singleton模式设计

Human-readable

让sfid变得可以阅读的解决思路:

0 - 00000 1 - 00001 2 - 00010 3 - 00011

4 - 00100 5 - 00101 6 - 00110 7 - 00111

8 - 01000 9 - 01001 A - 01010 B - 01011

C - 01100 D - 01101 E - 01110 F - 01111

G - 10000 H - 10001 I - 与L、1相似,略去

J - 10010 K - 10011 L - 与I、1相似,略去

M - 10100 N - 10101 O - 与0相似,略去

P - 10110 Q - 10111 R - 11000 S - 与5相似,略去

T - 11001 U - 11010 V - 11011 W - 11100

X - 11101 Y - 11110 Z - 11111

所以64位的SFID整形数,可以用64/5=12余4,一共13个符号既可以表示出来。可以用“012-34567-89ABC”的格式呈现优惠码,会员号等在系统用sfid表示的数据

12491575082415873361 = 1010 11010 10110 10111 11101 01011 01010 11000 01000 01001 10111 01010 10001 = AUP-QXBAR-89QAH

12491570832403129941 = 1010 11010 10110 10111 11001 01111 10100 10100 00000 01001 11001 10010 10101 = AUP-QTFMM-09TJN

12491566990856848639 = 1010 11010 10110 10111 10101 11111 11010 11101 00000 01001 00001 00111 11111 = AUP-QNZUX-0917Z

使用方法

  1. callback方式
var snowflake = require('snowflakeid-ro');
snowflake.getSnowflakeIDFactory(function(err, idGen) {
    idGen.next();                           // 生成一个id
    var idString = idGen.toString();
    console.log(idGen.toString());          // 按照10进制输出显示
    console.log(idGen.toString(16));        // 按照16进制输出显示
    
    var timestamp = idGen.getTimestamp(idString);  // timestamp = 1475143031137
    var hwid = idGen.getHwId(idString);    // hwid = 0x3f
    var shardId = idGen.getShardId(idString); // shardId = 0x0
    var seqId = idGen.getSeqId(idString); // seqId = 123
});
  1. 或者promise方式
var snowflake = require('snowflakeid-romens');
snowflake.getSnowflakeIDPromise()
         .then(function(sid){
             ...
         })
         .catch(function(err){
             ...
         });
  1. 转换为32进制显示
var snowflake = require('snowflakeid-ro');
var hrStr = snowflake.toHumanReadable("12491575082415873361");
console.log(hrStr); // AUP-QXBAR-89QAH
console.log(snowflake.fromHumanReadable(hrStr).toString(10)); // 12491575082415873361