分布式ID

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通常包括以下几个部分:

  1. 时间戳:占用42位,精确到毫秒级,表示生成ID的时间戳。由于使用的是毫秒级时间戳,因此雪花算法可以保证生成的ID在一段时间内是递增的。

  2. 机器ID:占用10位,表示生成ID的机器的唯一标识。在分布式系统中,每台机器都需要分配一个唯一的机器ID,以避免生成重复的ID。

  3. 序列号:占用12位,表示同一毫秒内生成的多个ID的序列号。当同一毫秒内生成的ID数量超过了4096个(2^12),序列号将从0开始重新计数。

雪花算法生成的ID具有以下特点:

  1. 全局唯一:在同一时刻、同一机器和同一毫秒内生成的ID是唯一的。

  2. 有序递增:由于时间戳的存在,生成的ID在整个分布式系统中是按照时间先后顺序递增的。

  3. 高性能:雪花算法是一种轻量级的算法,生成ID的速度非常快。

需要注意的是,雪花算法依赖于机器的时钟,如果系统时钟发生回拨,可能会导致生成重复的ID,因此在使用雪花算法时需要保证时钟的准确性。

3.基于数据库自增ID

每个数据库实例维护一个自增的序列,用于生成唯一ID。不同数据库使用的方式有所不同,比如MySQL的自增主键、Oracle的序列等。

优点:

  • 实现简单,ID单调自增,数值类型查询速度快

缺点:

  • DB单点存在宕机风险,无法扛住高并发场景

4.数据库集群

使用多台数据库,设置数据库的起始值和步长

优点:

  • 解决DB单点问题

缺点:

  • 不利于后续扩容,而且实际上单个数据库自身压力还是大,依旧无法满足高并发场景。

5.基于数据库的号段模式

基于数据库的号段模式(Segmented ID)是一种在分布式系统中生成唯一ID的方法,它通过预分配ID范围的方式来提高性能和减少数据库访问压力。下面是一种基于数据库的号段模式生成分布式ID的一般步骤:

  1. 创建ID生成表:在数据库中创建一个专门用于生成ID的表,比如命名为id_generator。表中通常包含以下字段:

    • table_name:标识生成ID的业务表名。
    • next_id:记录下一个可用的ID起始值。
    • max_id:记录当前号段的最大ID值。
    • step:每次预分配的号段大小,表示每个号段的ID数量。
  2. 初始化号段:当系统启动时,需要初始化号段表,将next_id设置为某个开始值,并且max_id设置为next_id + step。这个开始值可以根据业务需求,比如可以通过查询业务表中最大ID来设置。

  3. 分配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_idmax_id的值,并返回给你这个号段的起始值和结束值。

  4. 使用号段生成ID:获取到号段后,可以根据号段的起始值和结束值生成一系列连续的唯一ID。这些ID可以根据自己的需求进行格式化(如前缀、后缀等)。

  5. 号段用尽处理:在使用号段过程中,如果发现某一个号段的可用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还囊括了号段模式。

参考:

一口气说出9种分布式ID生成方式,阿里面试官都懵了 - 知乎 (zhihu.com)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YuuuZh。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值