当数据库面临分库分表时,无法依赖数据库自增主键来生成业务标识,或业务场景设计时为了防止自增id被外部撞库猜测数据,通常会考虑引入全局唯一标识生成器来解决此类问题。
介绍
目前市面上比较常见的基本为Twitter
开源的Snowflake
及其变种,Snowflake
的核心思想是将64bit
的二进制数字分为若干部分,每一部分都存储具有特定含义的数据,比如时间戳、机器ID、序列号等,最终生成全局唯一有序ID,标准算法如下图:
- 41位的时间戳部分可以支撑
pow(2,41)/1000/60/60/24/365
年,约等于 69 年。 - 如果系统部署在多机房,那么 10 位的机器 ID 可以继续划分为
2~3
位的 IDC 标示(可以支撑 4 个或者 8 个 IDC 机房)和7~8
位的 机器 ID(支持 128-256 台机器)。 - 12 位的序列号代表着每个节点每毫秒最多可以生成 4096 的 ID。
部署方式
雪花ID具有两种使用方式,一种是独立部署一套发号器,外部请求下发,另一种更为常见的做法是直接嵌入到应用内,使用Snowflake
工具类直接获取使用,当嵌入到应用内部时,可以考虑将机器ID部分,分散标识到不同业务系统。
缺点
时间回拨问题
Snowflake
算法设计很简单和巧妙,性能高效,具有全局唯一性、单调递增性和有业务含义的ID,但是它也有一定缺点,其中最大的缺点就是他依赖于系统的时间戳,一旦时间不准,就有可能生成重复的ID。如果是独立部署的发号器,如果发现系统时间不准,可以直接暂停发号,知道时间准确为止。
QPS低引起单调重复
如果发号器的QPS不高,例如每毫秒只能发一个ID,就会造成ID的末尾永远是1,如果在分库分表系统中使用ID作为分区间,就会造成库表分配的不均匀。
如何解决:
- 时间戳不记录毫秒而是记录秒,这样在一个时间区间内可以多发几个号,避免出现分库分表时数据分配不均。
- 生成的序列号的起始号可以做一下随机,这一秒是21,下一秒可以是30,这样也会保证均衡。