分布式ID所有生成方案

前言

在单体应用中,一般直接用表的自增ID或者UUID作为唯一标识。业务体量增大在分库分表之后,如何生成一个全局唯一的ID,就是一个关键的问题。

通常情况下,对于分布式ID来说,我们一般希望他具有以下几个特点:

● 全局唯一:必须保证全局唯一性,这个是最基本的要求。

● 高性能&高可用:需要保证ID的生成是稳定且高效的。

● 递增:根据不同的业务情况,有的会要求生成的ID呈递增趋势,也有的要求必须单调递增(后一个ID必须比前一个大),也有的没有严格要求。

分布式ID方案

具体的分布式ID有以下这些方案:

方案 全局唯一 高性能 / 高可用 递增性 / 有序性 依赖组件 适用场景
UUID 本地生成,高性能 无序 无需有序性的通用场景
数据库自增 单点瓶颈,低可用 严格递增 单库单表 低并发、强依赖递增的场景
号段模式 减少数据库访问 趋势递增(非严格) 数据库 中高并发、可接受 ID 不连续场景
Redis 集群支持高可用 严格递增 Redis 集群 高并发、需严格递增的场景
雪花算法 单机高性能 严格递增 时钟同步 高并发、需有序性的场景

UUID

UUID(Universally Unique Identifier)全局唯一标识符,是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。

标准的UUID格式为:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (8-4-4-4-12),共32个字符,通常由以下几部分的组合而成:当前日期和时间,时钟序列,全局唯一的IEEE机器识别号

优缺点

  • 优点: UUID的优点就是他的性能比较高,不依赖网络,本地就可以生成,使用起来也比较简单。

  • 缺点:长度过长和没有任何含义。一旦使用它作为全局唯一标识,就意味着在日后的问题排查和开发调试过程中会遇到很大的困难。

    不适合范围查询、不方便展示以及查询效率低等问题。

数据库自增

分布式ID也可以使用数据库的自增ID,但是这种实现中就要求一定是一个单库单表才能保证ID自增且不重复.

优缺点

  • 优点:使用简单,容易维护,查询效率高支持范围查询。
  • 缺点:一旦这个数据库挂了,那整个分布式ID的生成服务就挂了。而且还存在一个性能问题,如果高并发访问数据库的话,就会带来阻塞问题。

号段模式

号段模式是在数据库的基础上,为了解决性能问题而产生的一种方案。他的意思就是每次去数据库中取ID的时候取出来一批,并放在缓存中,然后下一次生成新ID的时候就从缓存中取。这一批用完了再去数据库中拿新的。

而为了防止多个实例之间发生冲突,需要采用号段的方式,即给每个客户端发放的时候按号段分开,如客户端A取的号段是1-1000,客户端B取的是1001-2000,客户端C取的是2001-3000。当客户端A用完之后,再来取的时候取到的是3001-4000。

优缺点

  • 优点:在同一个客户端中,生成的ID是顺序递增的。并且不需要频繁的访问数据库,也能提升获取ID的性能。
  • 缺点:是没办法保证全局顺序递增,也存在数据库的单点故障问题。

其实很多分库分表的中间件的主键ID的生成,主要采用的也是号段模式,如TDDL Sequence

Redis 实现

基于数据库可以实现,那么基于Redis也是可以的,我们可以依赖Redis的incr命令实现ID的原子性自增。R

优缺点

  • 优点:借助集群解决单点故障的问题,性能也比较高。
  • 缺点:存在数据丢失的情况,无论是那种持久化机制,都无法完全避免。

雪花算法

雪花算法(Snowflake)是由Twitter研发的一种分布式ID生成算法,它可以生成全局唯一且递增的ID。它的核心思想是将一个64位的ID划分成多个部分,每个部分都有不同的含义,包括时间戳、数据中心标识、机器标识和序列号等。

雪花算法生成的ID由以下几个部分组成:

  1. 符号位(1bit):固定为 0(保证 ID 为正数)。
  2. 时间戳(41bit):精确到毫秒级别,41位的时间戳可以容纳的毫秒数是2的41次幂,一年所使用的毫秒数是:365 * 24 * 60 * 60 * 1000,算下来可以使用69年。
  3. 数据中心标识(5bit):可以用来区分不同的数据中心。
  4. 机器标识(5bit):可以用来区分不同的机器。
  5. 序列号(12bit):同一毫秒内每台机器可生成 4096 个 ID。

优缺点

  • 优点:性能好、有序,比较灵活各部分位数可根据业务需求调整
  • 缺点:时钟回拨问题( 若机器时钟因硬件故障、时区调整或 NTP 同步等原因回退到之前的时间,可能生成重复 ID。);时间戳占用位数与有效期限制;单节点并发上限(12 位序列号允许单节点单毫秒生成 4096 个 ID,若瞬时并发超过该阈值(如秒杀场景),需等待下一毫秒,可能导致请求阻塞或业务延迟。)

第三方工具

百度 Uidgenerator

是百度开源基于 Java 语言实现的唯一 ID 生成器,是在雪花算法 Snowflake 的基础上做了一些改进,如支持自定义位数和生成策略等。

  • 优点

    • 高性能:支持每秒生成数百万个 ID,单个实例 QPS 能超过 6000000,可满足高并发场景需求。
    • 高可用性:支持多节点部署,某个节点宕机不影响系统正常运行。
    • 易于使用:提供简单易用的 API,便于集成到现有系统。
    • 可定制化:支持自定义机器 ID 和序列号生成方式,能根据实际需求定制。
    • 解决时钟回拨问题:通过采用 AtomicLong 类型的时间,并使用 incrementAndGet () 方法获取下一次时间,脱离了对服务器时间的依赖,避免了时钟回拨问题。
  • 缺点

    • 趋势自增:生成的 ID 是趋势自增的,在某些对 ID 随机性有要求的场景中不适用。
    • 依赖 MySQL:依赖 MySQL 做 workerId 分发,使用 MySQL 自增 Id 做 workId,用后即弃,增加了对数据库的依赖。
    • 时间范围有限:UidGenerator 的时间部分只有 28 位,默认只能承受 8.5 年。

美团 Leaf

兼具数据库号段模式和雪花算法两种方式,用户可以同时开启两种方式,也可以指定开启某种方式,能够根据不同业务场景灵活切换。

  • 优点

    • 支持多种模式:支持号段模式和雪花算法两种模式,可根据不同业务场景灵活选择。
    • 高性能和高可用:号段模式下,通过一次请求获取一批自增 ID,减少访库次数,降低数据库读写压力;在雪花算法模式下,也能提供较高的性能和可用性。
    • 全局唯一:能够保证生成的 ID 在全局范围内是唯一的。
    • 趋势递增:无论是号段模式还是雪花算法模式,都能保证生成的 ID 是趋势递增的,适合对 ID 有序性有要求的场景。
  • 缺点

    • 号段模式依赖数据库:号段模式下强依赖于数据库,如果数据库出现故障,可能会影响 ID 的生成。不过可以通过数据库集群等方式来提高可用性。
    • 雪花算法模式依赖时钟:雪花算法模式强依赖机器时钟,如果发生时钟回拨,可能导致发号重复或服务不可用。

滴滴 Tinyid

是滴滴用 Java 开发的一款分布式 ID 生成系统,基于数据库号段算法实现,扩展了 leaf - segment 算法,支持了多 db(master),同时提供了 java - client(SDK)使 ID 生成本地化,获得了更好的性能与可用性

  • 优点

    • 全局唯一:能够生成全局唯一的 long 型 ID。
    • 性能较高:通过将号段加载到内存中,ID 为本地生成,号段长度越长,QPS 越高,最高可达 1000w+。
    • 可用性较好:支持多 db 配置,只要有一台 server 存活,理论上服务就可用;即使 server 全挂,由于 client 有缓存,也能继续使用一段时间。
    • 功能丰富:支持批量获取 ID,还支持生成特定序列的 ID,如 1,3,5,7,9 等。
  • 缺点

    • 不保证严格递增:生成的 ID 是趋势递增,但不保证下一个 ID 一定比上一个大,不适合对 ID 单调性要求严格的场景。
    • ID 连续性问题:由于在 server 或 client 重启时,内存中预加载的号段会作废,下次请求会获得新号段,导致 ID 不连续,会浪费一部分 ID,不适合对 ID 连续性要求高的场景。
    • 不适用特定业务:生成的 ID 大部分是连续的,容易被扫库或测算出订单量等信息,不适合类似订单 ID 等对信息安全性要求高的业务。

总结

分布式 ID 生成的核心是平衡 唯一性、性能、有序性系统依赖UUID数据库自增 是入门方案,适合简单场景; 雪花算法及其变种(Uidgenerator、Leaf) 是中高频选择,兼顾性能与有序性; TinyidRedis 则面向极致性能需求,但需接受 ID 不连续或缓存依赖。

实际选型时,需结合业务规模、技术栈和未来扩展规划,对系统性能要求或者扩展性高的可优先选择成熟开源方案(如 Leaf、Tinyid),避免重复造轮子。

相关推荐
jack_xu1 小时前
高频面试题:如何保证数据库和es数据一致性
后端·mysql·elasticsearch
264玫瑰资源库1 小时前
问道数码兽 怀旧剧情回合手游源码搭建教程(反查重优化版)
java·开发语言·前端·游戏
pwzs1 小时前
Java 中 String 转 Integer 的方法与底层原理详解
java·后端·基础
东阳马生架构1 小时前
Nacos简介—2.Nacos的原理简介
java
Asthenia04122 小时前
InnoDB文件存储结构与Socket技术(从Linux的FD到Java的API)
后端
普if加的帕2 小时前
java Springboot使用扣子Coze实现实时音频对话智能客服
java·开发语言·人工智能·spring boot·实时音视频·智能客服
Asthenia04122 小时前
RocketMQ 消息不丢失与持久化机制详解-生产者与Broker之间的详解
后端
爱喝一杯白开水2 小时前
SpringMVC从入门到上手-全面讲解SpringMVC的使用.
java·spring·springmvc
王景程2 小时前
如何测试短信接口
java·服务器·前端