分布式系统中userId的生成
userId生成的策略类型
目前常见的userId生成策略主要有:
- 数据库自增id
UUID- 雪花算法
数据库自增id
简单明了,使用数据库中的主键自增即可实现
优点在于:
- 自动自增,可以作为索引提升数据库的查询效率
- 节省磁盘空间,相较于其他两种策略可以节省大量空间
- 查询、写入效率高
缺点在于:
- 在导入数据时可能存在id重复的问题
- 不适应与分布式架构,在该中存在id重复的问题
- 无法进行分表,拆表等操作,与分布式的缺陷类似
UUID
UUID(Universally Unique Identifier):它是由一组32个十六进制数字组成的字符串,总共分为无端,每段之间用连字符(-)隔开,包括连字符在内共36个字符
1 | // 生成UUID |
UUID基于硬件地址(MAC地址)、时间戳和随机因子来生成Id
优势在于:
- 几乎不可能重复,可以用于分布式系统
- 具有唯一性、高性能和高可用的特点
- 本地生成
缺点在于:
- 产生的值较长,足足有36个字符
- ID完全随机,没有任何顺序可言
- 可读性差,且ID不具有任何意义
- 字符串类型读写效率差
雪花算法(Snowflake)生成ID
Snowflake,雪花算法是由Twitter开源的分布式ID生成算法,以划分命名空间的方式将 64-bit位分割成多个部分,每个部分代表不同的含义。而 Java中64bit的整数是Long类型,所以在 Java 中 SnowFlake 算法生成的 ID 就是 long 来存储的。
- 第
1位占用1bit,其值始终是0,可看做是符号位不使用。 - 第
2位开始的41位是时间戳,41-bit位可表示2^41个数,每个数代表毫秒,那么雪花算法可用的时间年限是(1L<<41)/(1000L360024*365)=69年的时间。 - 中间的
10-bit位可表示机器数,即2^10 = 1024台机器,但是一般情况下我们不会部署这么台机器。如果我们对IDC(互联网数据中心)有需求,还可以将10-bit分5-bit给IDC,分5-bit给工作机器。这样就可以表示32个IDC,每个IDC下可以有32台机器,具体的划分可以根据自身需求定义。 - 最后
12-bit位是自增序列,可表示2^12 = 4096个数。
这样的划分之后相当于在一毫秒一个数据中心的一台机器上可产生4096个有序的不重复的
ID。但是我们IDC和机器数肯定不止一个,所以毫秒内能生成的有序ID数是翻倍的。
优点在于:
- 生成的
ID全局唯一 - 分布式算法,可以在多台机器上生成
ID - 生成的
ID为64位整数,Long类型,读写效率高
缺点在于:
- 依赖机器时钟:雪花算法使用了时间戳作为生成
ID的一部分,因此对于分布式系统来说,各个机器的时钟需要保持同步,否则可能会导致生成重复的ID。 - 有限的容量:雪花算法中的机器
ID和序列号都是固定长度的,因此在极端情况下,可能会达到容量上限,无法继续生成唯一的ID。 - 不适合特定场景(安全):雪花算法生成的
ID是递增的,如果对于一些需要保密性的场景,可能会暴露一些敏感信息,例如系统的使用频率和规模。
改进的方法:百度
UidGenerator和 美团分布式ID生成系统Leaf中snowflake模式都是在 snowflake 的基础上演进出来的
关于 百度-UidGenerator
UidGenerator是Java实现的, 基于Snowflake算法的唯一ID生成器。
UidGenerator以组件形式工作在应用项目中, 支持自定义workerId位数和初始化策略, 从而适用于docker等虚拟化环境下实例自动重启、漂移等场景。
在实现上, UidGenerator通过借用未来时间来解决sequence天然存在的并发限制; 采用RingBuffer来缓存已生成的UID, 并行化UID的生产和消费, 同时对CacheLine补齐,避免了由RingBuffer带来的硬件级「伪共享」问题. 最终单机QPS可达600万。
1 | // SpringBoot整合UidGenerator |
本文参考:


