这篇文章我我们来探讨一下分布式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上泄密问题,需要在使用上进行权衡利弊,同时在规范设置上进行一定策略来防泄密。