分布式唯一标识设计

当数据库面临分库分表时,无法依赖数据库自增主键来生成业务标识,或业务场景设计时为了防止自增id被外部撞库猜测数据,通常会考虑引入全局唯一标识生成器来解决此类问题。

介绍

目前市面上比较常见的基本为Twitter开源的Snowflake及其变种,Snowflake的核心思想是将64bit的二进制数字分为若干部分,每一部分都存储具有特定含义的数据,比如时间戳、机器ID、序列号等,最终生成全局唯一有序ID,标准算法如下图:
snowflake

  • 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作为分区间,就会造成库表分配的不均匀
如何解决:

  1. 时间戳不记录毫秒而是记录秒,这样在一个时间区间内可以多发几个号,避免出现分库分表时数据分配不均。
  2. 生成的序列号的起始号可以做一下随机,这一秒是21,下一秒可以是30,这样也会保证均衡。

参考

  1. 发号器:如何保证分库分表后 ID 的全局唯一性?
  2. 万亿级调用系统:微信序列号生成器架构设计及演变