连载中 10/16

开源选型:从 Leaf 到 UidGenerator

2026-06-10 · 4789 阅读 · 0 评论 · 0 赞

造轮子,还是买现成的

前九篇把原理讲透了:号段双 buffer、雪花时钟、workerID 分配、Redis 两本账。老王回头一看,团队真要手搓一套发号服务,光是 workerID 分配和回拨治理就得写两周——这还是「能跑」的水平,不是「可靠」的水平。他决定先看开源:美团 Leaf、百度 UidGenerator、滴滴 Tinyid,三家大厂各自踩过坑后沉淀的方案。逐个拆。

Leaf:双模式任选的美团方案

Leaf 是三家里功能最全的,一个 jar 包里装了两套引擎,按业务口味切换:

segment 模式:就是第 3、4 篇的 DB 号段 + 双 buffer 落地版。每个业务一个 biz_tag,内存双 buffer 异步预加载。它比原理篇多做了一件事——step 动态调整:根据每个号段的实际消耗速度,把号段长度动态缩放(默认在 10 分钟 QPS 到 100 万 QPS 之间伸缩),流量低谷少占号,高峰自动扩容,DB 压力更平滑。

snowflake 模式:第 5-8 篇的雪花落地版。workerID 交给 ZooKeeper 顺序节点自动分配,解决了「镜像克隆撞号」的人工隐患。但它有个明确的弱项——时钟回拨只告警不兜底:检测到回拨直接抛异常,不等待不切换。也就是说 snowflake 模式的回拨治理,Leaf 把难题留给了你(第 7 篇的三招得自己补)。

接入形态是 Java SDK,应用引入 jar 直连 DB,没有独立发号服务——少一个部署单元,也意味着每个应用都要配号段库的连接。

UidGenerator:RingBuffer 预生成的百度方案

UidGenerator 是雪花改良派。它先动了位分配:64 位切成 1 位符号 + 28 位秒级时间戳 + 22 位 workerID + 13 位序列。秒级时间戳只够用 8.5 年(毫秒级能撑 69 年),换来的是 workerID 手笔阔绰——22 位支持约 420 万节点。每秒序列 8192 个,中等流量绰绰有余,超出就等下一秒,反正秒级单位下等待的感知更粗。

真正的杀手锏是 CachedUidGenerator:启动时把未来一段时间的 ID 批量预生成进 RingBuffer 环形数组,取号就是从内存读一个指针位置,官方压测单机 600 万/s。代价要想清楚两点:一是 RingBuffer 里预生成的 ID,其时间位代表的是「生成时刻」而非「业务领取时刻」,按时间范围反查业务时会和领取时间有偏差;二是重启会丢弃 RingBuffer 里未用完的号,洞比双 buffer 更大。

依赖极简:纯 Java 实现,workerID 用 DB 表或配置分配即可,没有 ZooKeeper。

Tinyid:轻装上阵的滴滴方案

Tinyid 是号段阵营的极简派,只做 segment 模式,但给了两种接入形态:HTTP 方式,任何语言一个 GET 请求拿号,多语言团队的最爱;Java SDK 方式,本地缓存号段异步预加载,发号不出网。它的特色是接口设计——一次调用可以取一个号段、可以批量取 N 个号,号段长度还能按业务动态配置。

代价是没有雪花模式:强依赖 DB,DB 挂了号段打光就停服(降级方案见第 14 篇)。对纯粹要「数据库号段」的场景,它比 Leaf 更轻,代码量小到可以整个读完再决定要不要用。

横评一张表

维度Leaf segmentLeaf snowflakeUidGeneratorTinyid
发号模式DB 号段双 buffer雪花雪花改良 + RingBufferDB 号段
单调/趋势趋势递增毫秒级趋势秒级趋势趋势递增
时钟依赖无有,回拨仅告警有,秒级较粗无
外部依赖DBDB + ZKDB(分配 workerID)DB
吞吐量级千万级/s(本地号段)单机百万/s单机 600 万/sSDK 千万级/s
多语言不友好(Java SDK)不友好不友好HTTP 友好

决策树一锤定音

老王把选型画成四个问题,按序问下去:

一问:要严格单调吗?三个开源全是「趋势」不是「严格」,严格单调请回到集中式号段 + 单点,或者干脆用 DB 自增。

二问:团队是纯 Java 吗?不是,Tinyid 的 HTTP 形态直接入围;是,往下问。

三问:能接受洞和乱序吗?能,且要极致单机吞吐,UidGenerator Cached 上桌;不能,往叶子走。

四问:时钟运维靠谱吗?靠谱且机器规模可控,Leaf snowflake(补上第 7 篇回拨治理);不靠谱,Leaf segment——号段阵营对时钟零依赖,这正是它经久不衰的原因。

四个问题都落空再谈自研。不过提醒一句:Leaf segment 的核心逻辑不到千行,读完源码再「自研」,多半会发现最后写出来的是个 Leaf 换皮——那就直接用 Leaf。

小结

三大开源一句话:Leaf 双模式功能全,snowflake 回拨弱项要自己补;UidGenerator 吞吐之王,RingBuffer 的洞和时间语义要想清;Tinyid 轻量多语言,纯号段场景性价比最高。选型落定,还有一个隐蔽话题没聊:同样是趋势递增,为什么有的 ID 插表丝滑、有的却把 B+ 树搅得稀碎?下一篇专讲趋势递增的艺术。

☕
503

10 年全栈工程师 · 503咖啡馆主理人

#分布式ID#开源发号器#Leaf#UidGenerator#Tinyid

评论 (0)

热门推荐

连载中 11/22

主从搭建实操:从零配出一主两从

光讲原理不过瘾?手把手搭一主两从:my.cnf 六个参数、复制账号、GTID、CHANGE REPLICATION SOURCE TO、SHOW REPLICA STATUS 验收,附翻车排查清单。

#MySQL#主从复制#GTID#主从搭建#高可用
2026-05-07 · 10100 阅读 · 0 评论 · 0 赞
连载中 16/22

连接池:HikariCP 参数与连接风暴

连接池不是越大越好:8 核机器配 1000 连接反而更慢的数学原理,HikariCP 四个必调参数,maxLifetime 与 wait_timeout 的隐形陷阱。

#MySQL#连接池#HikariCP#maxLifetime#连接风暴
2026-05-10 · 9872 阅读 · 0 评论 · 0 赞
连载中 4/16

缓存穿透:恶意 ID 打穿 MySQL 的四道防线

请求的数据在缓存和数据库里都不存在时,缓存形同虚设。聊聊参数校验、空值缓存、布隆过滤器、限流熔断四道防线的原理与组合打法。

#Redis#缓存穿透#布隆过滤器#高可用
2026-05-16 · 9293 阅读 · 21 评论 · 287 赞