分布式 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?有啥心得,欢迎留言聊聊!

相关推荐
uzong20 分钟前
技术故障复盘模版
后端
GetcharZp1 小时前
基于 Dify + 通义千问的多模态大模型 搭建发票识别 Agent
后端·llm·agent
桦说编程1 小时前
Java 中如何创建不可变类型
java·后端·函数式编程
IT毕设实战小研1 小时前
基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
java·开发语言·spring boot·后端·spring·毕业设计·课程设计
wyiyiyi2 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
阿华的代码王国3 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
Jimmy3 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
AntBlack3 小时前
不当韭菜V1.1 :增强能力 ,辅助构建自己的交易规则
后端·python·pyqt
bobz9654 小时前
pip install 已经不再安全
后端
寻月隐君4 小时前
硬核实战:从零到一,用 Rust 和 Axum 构建高性能聊天服务后端
后端·rust·github