0%

分布式ID生成策略

这篇文章我我们来探讨一下分布式ID常用的几种生成策略思想。

UUID

UUID(Universally Unique Identifier)的标准形式包含32个16进制数字,以短划线(-)分为五段,形式为8-4-4-4-12的36个字符,示例:

1
123e4567-e89b-12d3-a456-426655440000

目前为止业界一共有5种方式生成 UUID,详情参见 IETF 发布的UUID规范,更多可参考 维基百科

UUID的特点如下:

  • 优点:本地生;性能非常高;无序

  • 缺点:

    • 生成的 UUID 不适合做位数据库主键或者索引字段。生成的 UUID 长度长,无序。数据库索引一般是 B+树,无序数据相比于有序的数据,会导致更多次的页拆分,较长的数据也会导致索引页快速增长
    • time-base 算法生成的 UUID 可能会存在 MAC 地址泄漏的安全风险
  • 场景:非索引键 ID 生成,对性能要求较高,对顺序,长度没有较高要求的场景

雪花算法

Snowflake 是 Twitter 开源的分布式 ID 生成算法。其核心思想是对二进制的bit位进行划分构成,从高位到地位一次是:

  • 1bit符号位:预留的符号位,恒为零

  • 41bit时间戳位: 41位的时间戳可以容纳的毫秒数是2的41次幂,一年所使用的毫秒数是:365 * 24 * 60 * 60 * 1000。通过计算可知结果约等于69.73年

    1
    Math.pow(2, 41) / (365 * 24 * 60 * 60 * 1000L);
  • 10bit工作进程位: 其中高位5bit是数据中心ID,低位5bit是工作节点ID,做多可以容纳1024个节点

  • 12bit序列号位: 每个节点每毫秒0开始不断累加,最多可以累加到4095,一共可以产生4096个ID

雪花算法的特点如下:

  • 优点:ID都是趋势递增,生成性能高。
  • 缺点:强依赖机器时钟,如果机器上时钟回拨,会导致发号重复,需要解决时钟回拨问题。
  • 场景:需要无序不被猜测的 ID,并且需要具备一定的高性能,可以使用 Snowflake 和类 Snowflake 算法。

其他类似 MongoDB ObjectID 的类 Snowflake 算法,也具有同样的特点。

号段思想

号段思想即是依赖于某一个载体,每次获取一批次(指定步长)的序列号供使用,再要使用完之前再向载体索取下一批次序列号,在保证一定吞吐量的同时又确保能达到一定的性能。

当前在使用分布式ID的同时,绝大部分会使用到数据库,所以用数据库来作为载体实现。其具有一下特性:

  • 优点:批次具有缓存特性,能在一定程度上提高可用性,能保证顺序性
  • 缺点:因为有序性,故容易泄露使用序列号的业务数据秘密;同时需要有载体依赖;

开源组件

Leaf

Leaf 是美团开源的分布式id生成服务,当前支持雪花和号段两种模式:

  • Leaf-snowflake:在雪花算法的基础上,利用ZooKeeper解决了时钟回拨的问题,但同时提高了系统的复杂度
  • Leaf-segment:是号段思想的实现,利用号段缓存提高了其性能和可用性

sharding-jdbcsharding-jdbc

sharding-jdbcsharding-jdbc 支持了 UUID、雪花、Leaf等生成策略的集成

uid-generator

uid-generator 是百度开源的对雪花算法实现的id生成器,特点在于用户可以自己去定义 WorkID 的生成策略,WorkID 默认提供的策略是:应用启动时由数据库分配

cell

Cell 是对号段思想的一种实现方式,同时也是类雪花算法的一种实现,具有高性能性、规范性以及可理解性等特点;但其无法直接避免从ID上泄密问题,需要在使用上进行权衡利弊,同时在规范设置上进行一定策略来防泄密。