1.基于UUID
UUID(Universally Unique Identifier):它是一种128位的唯一标识符,几乎可以被认为是全球唯一的。UUID的生成不依赖于机器或时间戳,因此可以在分布式系统中生成唯一ID。但UUID却并不适用于实际的业务需求。像用作订单号UUID
这样的字符串没有丝毫的意义,看不出和订单相关的有用信息;而对于数据库来说用作业务主键ID
,它不仅是太长还是字符串,存储性能差查询也很耗时,所以不推荐用作分布式ID
。
优点:
- 生成足够简单,本地生成无网络消耗,具有唯一性
缺点:
- 无序的字符串,不具备趋势自增特性
- 没有具体的业务含义
- 长度过长16 字节128位,36位长度的字符串,存储以及查询对MySQL的性能消耗较大,MySQL官方明确建议主键要尽量越短越好,作为数据库主键
UUID
的无序性会导致数据位置频繁变动,严重影响性能。
2.雪花算法(Snowflake)
雪花算法(Snowflake Algorithm)是一种用于生成唯一的ID标识符的算法。它最初由Twitter开发并开源,用于解决分布式系统中的ID生成问题。
雪花算法的核心思想是将一个64位的ID标识符分成几个不同的部分,每个部分用于表示不同的信息。具体来说,一个雪花算法生成的ID通常包括以下几个部分:
-
时间戳:占用42位,精确到毫秒级,表示生成ID的时间戳。由于使用的是毫秒级时间戳,因此雪花算法可以保证生成的ID在一段时间内是递增的。
-
机器ID:占用10位,表示生成ID的机器的唯一标识。在分布式系统中,每台机器都需要分配一个唯一的机器ID,以避免生成重复的ID。
-
序列号:占用12位,表示同一毫秒内生成的多个ID的序列号。当同一毫秒内生成的ID数量超过了4096个(2^12),序列号将从0开始重新计数。
雪花算法生成的ID具有以下特点:
-
全局唯一:在同一时刻、同一机器和同一毫秒内生成的ID是唯一的。
-
有序递增:由于时间戳的存在,生成的ID在整个分布式系统中是按照时间先后顺序递增的。
-
高性能:雪花算法是一种轻量级的算法,生成ID的速度非常快。
需要注意的是,雪花算法依赖于机器的时钟,如果系统时钟发生回拨,可能会导致生成重复的ID,因此在使用雪花算法时需要保证时钟的准确性。
3.基于数据库自增ID
每个数据库实例维护一个自增的序列,用于生成唯一ID。不同数据库使用的方式有所不同,比如MySQL的自增主键、Oracle的序列等。
优点:
- 实现简单,ID单调自增,数值类型查询速度快
缺点:
- DB单点存在宕机风险,无法扛住高并发场景
4.数据库集群
使用多台数据库,设置数据库的起始值和步长
优点:
- 解决DB单点问题
缺点:
- 不利于后续扩容,而且实际上单个数据库自身压力还是大,依旧无法满足高并发场景。
5.基于数据库的号段模式
基于数据库的号段模式(Segmented ID)是一种在分布式系统中生成唯一ID的方法,它通过预分配ID范围的方式来提高性能和减少数据库访问压力。下面是一种基于数据库的号段模式生成分布式ID的一般步骤:
-
创建ID生成表:在数据库中创建一个专门用于生成ID的表,比如命名为
id_generator
。表中通常包含以下字段:table_name
:标识生成ID的业务表名。next_id
:记录下一个可用的ID起始值。max_id
:记录当前号段的最大ID值。step
:每次预分配的号段大小,表示每个号段的ID数量。
-
初始化号段:当系统启动时,需要初始化号段表,将
next_id
设置为某个开始值,并且max_id
设置为next_id + step
。这个开始值可以根据业务需求,比如可以通过查询业务表中最大ID来设置。 -
分配ID号段:当需要生成一个新的ID时,首先从
id_generator
表中获取对应业务表的号段。可以使用数据库事务来确保并发情况下的安全性。例如,使用如下的SQL查询:UPDATE id_generator SET next_id = next_id + step, max_id = next_id + step WHERE table_name = 'your_table_name' RETURNING next_id, max_id;
这个查询会更新
next_id
和max_id
的值,并返回给你这个号段的起始值和结束值。 -
使用号段生成ID:获取到号段后,可以根据号段的起始值和结束值生成一系列连续的唯一ID。这些ID可以根据自己的需求进行格式化(如前缀、后缀等)。
-
号段用尽处理:在使用号段过程中,如果发现某一个号段的可用ID已经被分配完,则需要重新分配新的号段。可以通过一个定时任务或者触发器来检测号段使用情况,当号段使用剩余数量低于某个阈值时,触发重新分配新的号段。
通过这种方式,我们可以避免每次生成ID都访问数据库,减少数据库的压力,提高ID生成的性能。需要注意的是,在高并发场景下,需要考虑并发冲突和事务的隔离级别,以保证ID的唯一性和正确性。
6.基于Redis的自增
使用redis的incr命令
# 设置初始值
SET my_table_id 1000
# 生成ID
INCR my_table_id
使用Redis自增生成的ID不是全局唯一的,而是在Redis实例范围内唯一。如果有多个应用程序或分布式节点都连接了同一个Redis实例,可能会生成重复的ID。如果需要在整个分布式系统中保证ID的全局唯一性,则需要结合其他机制,如使用分布式锁或组合其他ID生成算法。
另外,使用Redis自增生成的ID是有序递增的,这在一些场景下可能是有用的,比如排序和索引。但要注意Redis的自增机制是线性递增的,可能会受到并发请求的限制。如果需要更高的性能,可以考虑利用Redis的分片和集群技术来实现水平扩展和高可用性。
7.百度(uid-generator)
8.美团(Leaf)
9.滴滴(Tinyid)
后三者都是基于雪花算法实现的,不同的是Leaf和Tinyid还囊括了号段模式。