大佬的总结:https://segmentfault.com/a/1190000022717820
做个表格汇总一下
方式 | 生成方式 | 优点 | 缺点 | 是否推荐 |
---|---|---|---|---|
UUID | jdk自带 | - 生成足够简单,本地生成无网络消耗,具有唯一性 |
- 无序的字符串,不具备趋势自增特性 - 没有具体的业务含义 - 长度过长16 字节128位,36位长度的字符串,存储以及查询对MySQL的性能消耗较大,MySQL官方明确建议主键要尽量越短越好,作为数据库主键 UUID 的无序性会导致数据位置频繁变动,严重影响性能。 |
|
基于数据库自增ID | 基于数据库的auto_increment自增ID | - 实现简单,ID单调自增,数值类型查询速度快 |
- DB单点存在宕机风险,无法扛住高并发场景 |
|
基于数据库集群模式 | 设置起始值和自增步长 | - 解决DB单点问题 |
- 不利于后续扩容,而且实际上单个数据库自身压力还是大,依旧无法满足高并发场景。 |
|
基于Redis模式 | 利用redis的 incr命令实现ID的原子性自增 | - 效率高 - 具有隔离性 |
- 需要考虑redis持久化的问题 - RDB会定时打一个快照进行持久化,假如连续自增但redis没及时持久化,而这会Redis挂掉了,重启Redis后会出现ID重复的情况。 - AOF会对每条写命令进行持久化,即使Redis挂掉了也不会出现ID重复的情况,但由于incr命令的特殊性,会导致Redis重启恢复的数据时间过长。 |
|
基于雪花算法 | 见下 | |||
百度(uid-generator) | 基于Snowflake算法实现的,与原始的snowflake算法不同在于,uid-generator支持自定义时间戳、工作机器ID和 序列号 等各部分的位数,而且uid-generator中采用用户自定义workId的生成策略。 | |||
美团(Leaf) | 同时支持号段模式和snowflake算法模式,可以切换使用 | |||
滴滴(Tinyid) | 基于号段模式原理实现的与Leaf如出一辙 |
雪花算法
Snowflake ID组成结构:正数位(占1比特)+ 时间戳(占41比特)+ 机器ID(占5比特)+ 数据中心(占5比特)+ 自增值(占12比特),总共64比特组成的一个Long类型。
- 第一个bit位(1bit):Java中long的最高位是符号位代表正负,正数是0,负数是1,一般生成ID都为正数,所以默认为0。
- 时间戳部分(41bit):毫秒级的时间,不建议存当前时间戳,而是用(当前时间戳 - 固定开始时间戳)的差值,可以使产生的ID从更小的值开始;41位的时间戳可以使用69年,(1L << 41) / (1000L _60 _60 _24 _365) = 69年
- 工作机器id(10bit):也被叫做workId,这个可以灵活配置,机房或者机器号组合都可以。
- 序列号部分(12bit),自增值支持同一毫秒内同一个节点可以生成4096个ID