目录
一 为什么需要分布式 ID
一个唯一 ID 在一个分布式系统中是非常重要的一个业务属性,其中包括一些如订单 ID,消息 ID ,会话 ID,他们都有一些共有的特性:
- 全局唯一
- 趋势递增
全局唯一是为了唯一标识某次请求,某个业务;趋势递增是考虑到顺序写磁盘性能好,读能够充分的利用上数据库的索引。
二 如何生成分布式 ID
2.1 数据库自增 ID
MySQL中的自增属性 auto_increment 来生成全局唯一 ID,来保证趋势递增。
- 优点:简单方便,有序递增,方便排序和分页
- 缺点:生成 ID 过程强依赖于 DB,主库挂了写失败;数据库由于是单节点写入,并发写入性能不高。
改进:将数据库水平拆分,假设拆分为两个数据库 A 库和 B 库。A 库的递增方式是0,2,4,6。B 库的递增方式是1,3,5,7。这样的方式可以提高系统可用性,且 ID 也是趋势递增的。但是会出现如下问题:
- 想要扩容主库,提高性能变的困难,之前已经定义好了 A、B 库递增的步数,新加的数据库不好加入进来,水平扩展困难。
- 强依赖于数据库,如果其中一台挂掉了那就不是绝对递增了。
2.2 UUID 生成
UUID 是通用唯一识别码(Universally Unique Identifier)的缩写,开放软件基金会(OSF)规范定义了包括网卡 MAC 地址、时间戳、名字空间(Namespace)、随机或伪随机数、时序等元素。利用这些元素来生成 UUID。UUID 是由 128 位二进制组成,一般转换成十六进制,然后用 String 表示。可以通过 JDK 的 UUID 类本地生成 UUID。
- 优点:本地生成没有了网络之类的消耗,所以效率非常高。
- 缺点: 生成的 ID 是无需的,不能做到趋势递增;由于是字符串并且不是递增,不适合作为主键存储。
2.3 本地时间
可以利用本地的毫秒数加上一些业务 ID 来生成唯一 ID,这样可以做到趋势递增,并且是在本地生成效率也很高。
- 优点:本地生成 ID,没有网络消耗;生成的 ID 趋势递增;生成 ID 查询效率高
- 缺点:如果并发量超过 1000,会生成重复的 ID,不能保证 ID 的唯一性。当然,使用微秒可以降低冲突概率,但每秒最多只能生成1000000个ID,再多的话就一定会冲突了,所以使用微秒并不从根本上解决问题。
2.4 snowflake 算法
snowflake 是 twitter 开源的分布式 ID 生成算法,其核心思想为,一个 long 型的 ID:
- 41 bit 作为毫秒数
- 10 bit 作为机器编号(5个 bit 表示数据中心,5个 bit 表示机器ID)
- 12 bit 作为毫秒内流水号
- 41 bit 的时间戳长度可以使用 69 年。
- 10 bit 机器编号可以支持部署 1024 个节点。
- 12 bit 的流水号支持每个节点每毫秒产生 4096 个 ID。
这个算法单机每秒内理论上最多可以生成 1000*(2^12),也就是 400W 的 ID,完全能满足业务的需求。
2.5 snowflake 算法优化
百度的 uid-generator 和美团的 Leaf 基本上是对 snowflake 的优化改进。
- 百度的 uid-generator
https://github.com/baidu/uid-generator
- 美团 Leaf
https://github.com/zhuzhong/idleaf
三 参考文档
https://mp.weixin.qq.com/s/0H-GEXlFnM1z-THI8ZGV2Q
https://github.com/crossoverJie/JCSprout/blob/master/docs/distributed/ID-generator.md