分布式 ID 方案盘点:单机自增主键/UUID/SnowFlake/Redis/ZooKeeper/Leaf-Segment

分布式 ID 方案大盘点:从常见方案到美团 Leaf-Segment 的亮点

Hey,大家好,今天咱们来聊聊分布式 ID 这个分布式系统里绕不开的话题。分布式 ID 的设计目标是全局唯一、高效生成,还要尽量满足业务需求,比如有序性、可读性啥的。咱们先盘点一下常见的方案和具体的 ID 名称,再重点剖析美团的 Leaf-Segment 方案,看看它到底有啥过人之处。


常见分布式 ID 方案与具体名称

分布式 ID 方案五花八门,下面是几个常见的,带上它们的"学名"和特点:

  1. UUID(通用唯一标识符)

    • ID 名称 :UUID,比如 550e8400-e29b-41d4-a716-446655440000
    • 特点:128 位,36 个字符(含连字符),基于随机数或时间 + MAC 地址生成。
    • 优点:简单,生成不依赖网络,唯一性有保障。
    • 缺点:太长、无序,存数据库占空间,索引效率低。
  2. 数据库自增 ID

    • ID 名称 :通常叫 Auto-Increment ID,比如 MySQL 的 id 列,1、2、3 这样递增。
    • 特点:依赖数据库的 AUTO_INCREMENT,单表唯一。
    • 优点:简单、有序,单机无敌。
    • 缺点:分布式下单点压力大,扩展性差。
  3. Snowflake(雪花算法)

    • ID 名称 :Snowflake ID,比如 690174210123456789(64 位整型)。
    • 特点:Twitter 提出的,结构是 41 位时间戳 + 10 位机器 ID + 12 位序列号。
    • 优点:高效、有序,单机每毫秒能生成 4096 个。
    • 缺点:依赖时钟,时钟回拨可能重复,机器 ID 得手动配。
  4. Redis 生成 ID

    • ID 名称 :一般叫 Redis Incr ID,比如 1000110002
    • 特点:用 Redis 的 INCR 命令递增生成。
    • 优点:简单、高性能,支持分布式。
    • 缺点:依赖 Redis,持久化得自己搞,宕机可能丢号。
  5. Zookeeper 生成 ID

    • ID 名称 :常叫 Zookeeper Sequential ID,比如 znode-0000000001
    • 特点:利用 Zookeeper 顺序节点生成。
    • 优点:强一致性,有序。
    • 缺点:性能一般,依赖 Zookeeper,适合低并发场景。
  6. 美团 Leaf

    • ID 名称 :Leaf ID,分两种:Leaf-Segment ID(号段模式,如 1000001)和 Leaf-Snowflake ID
    • 特点:支持号段模式和 Snowflake 两种,灵活性高。
    • 优点:高性能、低依赖,后文细聊。
    • 缺点:号段模式可能浪费 ID,配置稍复杂。

美团 Leaf-Segment 方案:深度剖析与优势

美团的 Leaf 是开源的分布式 ID 生成框架,提供了两种模式:Leaf-Segment(号段模式)和 Leaf-Snowflake。咱们重点聊聊 Leaf-Segment,因为它在实际业务中用得特别多,尤其适合高并发场景。

Leaf-Segment 的工作原理

Leaf-Segment 的核心思路是"预分配号段":

  1. 号段预取 :服务启动时,从数据库(比如 MySQL)拿一段 ID 范围,比如 [1000, 2000)
  2. 内存生成:服务把这段号段加载到内存,客户端请求 ID 时直接从内存递增返回,比如 1000、1001、1002。
  3. 动态更新 :号段用完前,异步去数据库再拿一段,比如 [2000, 3000),无缝衔接。

数据库表大概长这样:

sql 复制代码
CREATE TABLE leaf_segment (
    biz_tag VARCHAR(32) PRIMARY KEY, -- 业务标签,比如 "order"
    max_id BIGINT NOT NULL,         -- 当前最大 ID
    step INT NOT NULL,              -- 号段步长,比如 1000
    update_time TIMESTAMP           -- 更新时间
);
INSERT INTO leaf_segment (biz_tag, max_id, step) VALUES ('order', 1000, 1000);
一个实际例子

假设订单系统用 Leaf-Segment:

  • 服务 A 启动,拿 [1000, 2000)
  • 客户端请求 100 个 ID,A 从内存返回 1000 到 1099。
  • 快用完时(比如到 1900),异步请求新号段 [2000, 3000)
  • 数据库里 max_id 更新为 3000,步长不变。
Leaf-Segment 的优势
  1. 高性能

    • 为啥:ID 生成全在内存,走的是本地递增,基本没网络开销。
    • 数据说话:美团实测 QPS 能到几万甚至更高,比直接读数据库快几百倍。
    • 对比:Snowflake 每毫秒 4096 个上限,Leaf-Segment 靠步长调整,单机轻松破万。
  2. 低数据库依赖

    • 为啥:号段用完才访问一次数据库,平时都不用连。
    • 好处:数据库压力从"每次请求都访问"降到"几千次请求访问一次",抗住了高并发。
    • 对比:数据库自增 ID 每条都得找数据库,QPS 一高就崩。
  3. 平滑扩容

    • 为啥:每个服务独立拿号段,互不干扰,加节点不影响已有逻辑。
    • 例子:订单系统从 3 台扩到 5 台,每台拿自己的号段,零迁移。
    • 对比:Snowflake 扩容得调整机器 ID,配置麻烦。
  4. 支持业务隔离

    • 为啥 :用 biz_tag 区分业务,订单用 order,用户用 user,号段互不冲突。
    • 好处:一个系统支持多业务,ID 前缀还能加区分。
    • 对比:UUID 和 Snowflake 没这种天然隔离,得自己拼字段。
  5. 容错性强

    • 为啥:数据库挂了,内存里的号段还能撑一阵。
    • 例子:步长 1000,数据库宕机 1 分钟,高峰每秒 100 请求也能撑 10 秒。
    • 对比:Redis 或数据库自增一旦挂,ID 生成直接停。
Leaf-Segment 的小瑕疵

当然,没啥是完美的:

  • ID 不严格连续 :服务重启可能丢号段,比如 [1500, 2000) 没用完就浪费了。
  • 步长配置:步长太大浪费 ID,太小频繁访问数据库,得调平衡。
  • 部署稍复杂:得搭个服务管理号段,比 UUID 直接调 API 多点成本。

和其他方案对比

  • VS UUID:Leaf-Segment 有序、短小,存数据库友好,UUID 太乱太长。
  • VS Snowflake:Leaf-Segment 不怕时钟回拨,依赖更少,但 Snowflake 单机更简单。
  • VS Redis:Leaf-Segment 持久化靠数据库更稳,Redis 得自己搞备份。

总结

分布式 ID 方案各有千秋,UUID 简单粗暴,Snowflake 高效有序,Leaf-Segment 则在性能和实用性上找到了甜蜜点。它的号段模式把数据库压力降到最低,又能扛高并发,还支持业务隔离,难怪美团拿它干大事。你们公司用啥方案生成 ID?有啥心得,欢迎留言聊聊!

相关推荐
utmhikari2 分钟前
【架构艺术】Go语言微服务monorepo的代码架构设计
后端·微服务·架构·golang·monorepo
蜡笔小新星5 分钟前
Flask项目框架
开发语言·前端·经验分享·后端·python·学习·flask
计算机学姐9 分钟前
基于Asp.net的驾校管理系统
vue.js·后端·mysql·sqlserver·c#·asp.net·.netcore
欢乐少年19042 小时前
SpringBoot集成Sentry日志收集-3 (Spring Boot集成)
spring boot·后端·sentry
浪九天6 小时前
Java直通车系列13【Spring MVC】(Spring MVC常用注解)
java·后端·spring
uhakadotcom7 小时前
Apache CXF 中的拒绝服务漏洞 CVE-2025-23184 详解
后端·面试·github
uhakadotcom7 小时前
CVE-2025-25012:Kibana 原型污染漏洞解析与防护
后端·面试·github
uhakadotcom7 小时前
揭秘ESP32芯片的隐藏命令:潜在安全风险
后端·面试·github
uhakadotcom7 小时前
Apache Camel 漏洞 CVE-2025-27636 详解与修复
后端·面试·github
uhakadotcom7 小时前
OpenSSH CVE-2025-26466 漏洞解析与防御
后端·面试·github