8种分布式ID解决方案
- 1、UUID
- 2、数据库自增ID
- 2.1、主键表
- 2.2、ID自增步长设置
- 3、号段模式
- 4、Redis INCR
- 5、雪花算法
- 6、美团(Leaf)
- 7、百度(Uidgenerator)
- 8、滴滴(TinyID)
1、UUID
UUID(Universally Unique Identifier
)是基于当前时间、计数器(counter)和硬件标识(通常为无线网卡的MAC地址)等数据计算生成的。包含32个16进制数字,以连字号分为五段,形式为8-4-4-4-12的36个字符,可以生成全球唯一的编码并且性能高效。
JDK提供了UUID生成工具,代码如下:
import java.util.UUID;
public class Test {
public static void main(String[] args) {
System.out.println(UUID.randomUUID());
}
}
输出如下
b0378f6a-eeb7-4779-bffe-2a9f3bc76380
UUID完全可以满足分布式唯一标识,但是在实际应用过程中一般不采用,有如下几个原因:
- 存储成本高: UUID太长,16字节128位,通常以36长度的字符串表示,很多场景不适用。
- 信息不安全: 基于MAC地址生成的UUID算法会暴露MAC地址,曾经梅丽莎病毒的制造者就是根据UUID寻找的。
- 不符合MySQL主键要求: MySQL官方有明确的建议主键要尽量越短越好,因为太长对MySQL索引不利:如果作为数据库主键,在InnoDB引擎下,UUID的无序性可能会引起数据位置频繁变动,严重影响性能。
2、数据库自增ID
利用Mysql的特性ID自增,可以达到数据唯一标识,但是分库分表后只能保证一个表中的ID的唯一,而不能保证整体的ID唯一。为了避免这种情况,我们有以下两种方式解决该问题。
2.1、主键表
通过单独创建主键表维护唯一标识,作为ID的输出源可以保证整体ID的唯一。
.2、ID自增步长设置
我们可以设置Mysql主键自增步长,让分布在不同实例的表数据ID做到不重复,保证整体的唯一。
3、号段模式
号段模式是当下分布式ID生成器的主流实现方式之一。其原理如下:
- 号段模式每次从数据库取出一个号段范围,加载到服务内存中。业务获取时ID直接在这个范围递增取值即可。
- 等这批号段ID用完,再次向数据库申请新号段,对max_id字段做一次update操作,新的号段范围是(
max_id
,max_id +step
]。4、Redis INCR
基于全局唯一ID的特性,我们可以通过Redis的INCR命令来生成全局唯一ID。
Redis分布式ID的简单案例
/** * Redis 分布式ID生成器 */ @Component public class RedisDistributedId { @Autowired private StringRedisTemplate redisTemplate; private static final long BEGIN_TIMESTAMP = 1659312000l; /** * 生成分布式ID * 符号位 时间戳[31位] 自增序号【32位】 * @param item * @return */ public long nextId(String item){ // 1.生成时间戳 LocalDateTime now = LocalDateTime.now(); // 格林威治时间差 long nowSecond = now.toEpochSecond(ZoneOffset.UTC); // 我们需要获取的 时间戳 信息 long timestamp = nowSecond - BEGIN_TIMESTAMP; // 2.生成序号 --》 从Redis中获取 // 当前当前的日期 String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd")); // 获取对应的自增的序号 Long increment = redisTemplate.opsForValue().increment("id:" + item + ":" + date); return timestamp << 32 | increment; } }
5、雪花算法
Snowflake,雪花算法是有Twitter开源的分布式ID生成算法,以划分命名空间的方式将64bit位分割成了多个部分,每个部分都有具体的不同含义,在Java中64Bit位的整数是Long类型,所以在Java中Snowflake算法生成的ID就是long来存储的。具体如下
- 第一部分: 占用1bit,第一位为符号位,不适用
- 第二部分: 41位的时间戳,41bit位可以表示241个数,每个数代表的是毫秒,那么雪花算法的时间年限是
(241)/(1000×60×60×24×365)=69
年- 第三部分: 10bit表示是机器数,即
2^ 10 = 1024
台机器,通常不会部署这么多机器- 第四部分: 12bit位是自增序列,可以表示
2^12=4096
个数,一秒内可以生成4096个ID,理论上snowflake方案的QPS约为409.6w/s
6、美团(Leaf)
由美团开发,开源项目链接:
- https://github.com/Meituan-Dianping/Leaf
Leaf同时支持号段模式和snowflake算法模式,可以切换使用。
snowflake模式依赖于ZooKeeper,不同于原始snowflake算法也主要是在workId的生成上,Leaf中workId是基于ZooKeeper的顺序Id来生成的,每个应用在使用Leaf-snowflake时,启动时都会都在Zookeeper中生成一个顺序Id,相当于一台机器对应一个顺序节点,也就是一个workId。
号段模式是对直接用数据库自增ID充当分布式ID的一种优化,减少对数据库的频率操作。相当于从数据库批量的获取自增ID,每次从数据库取出一个号段范围,例如 (1,1000] 代表1000个ID,业务服务将号段在本地生成1~1000的自增ID并加载到内存。
7、百度(Uidgenerator)
源码地址:
- https://github.com/baidu/uid-generator
中文文档地址:
- https://github.com/baidu/uid-generator/blob/master/README.zh_cn.md
UidGenerator是百度开源的Java语言实现,基于Snowflake算法的唯一ID生成器。它是分布式的,并克服了雪花算法的并发限制。单个实例的QPS能超过6000000。需要的环境:JDK8+,MySQL(用于分配WorkerId)。
8、滴滴(TinyID)
由滴滴开发,开源项目链接:
- https://github.com/didi/tinyid
Tinyid是在美团(Leaf)的
leaf-segment
算法基础上升级而来,不仅支持了数据库多主节点模式,还提供了tinyid-client
客户端的接入方式,使用起来更加方便。但和美团(Leaf)不同的是,Tinyid只支持号段一种模式不支持雪花模式。Tinyid提供了两种调用方式,一种基于Tinyid-server
提供的http方式,另一种Tinyid-client
客户端方式。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
2022-03-07 Spring事务的基本原理
2022-03-07 不用任何框架,Java 就能实现定时任务的 3 种方法