连载中 3/16

步长与号段:DB 发号的第一正解

2026-06-06 · 6081 阅读 · 0 评论 · 0 赞

从救急到正解,只差一个观念

UUID 被否掉之后,老王回头重新打量第 1 篇的步长方案。它能救急,说明方向没错:继续用数据库发号,但要批量。步长方案的毛病是每张业务表自己管自己的号段;把发号这件事从业务表里抽出来,放到一张独立的发号表里,一次领一段,内存里慢慢发——这就是号段模式,DB 发号的第一正解。

核心思想:一次一个号,不如一次一段号

先看发号表的骨架,就三个字段(示意):

id_alloc 表
  biz_tag   业务标识,比如订单线、优惠券线各占一行
  max_id    当前已发到的最大号
  step      每次领取的段长,比如 1000

发号服务取号段的动作是一个事务:

UPDATE id_alloc SET max_id = max_id + step WHERE biz_tag = order_tag;
SELECT max_id, step FROM id_alloc WHERE biz_tag = order_tag;
提交事务,拿到号段区间:[max_id - step + 1, max_id]

注意 UPDATE 自带行锁,多个发号实例并发领取也不会拿到同一段——唯一性由 DB 行锁保证。服务拿到号段后放进内存,业务请求来了就从内存里取下一个号,用完再回来领下一段。step 设 1000,DB 的写压力瞬间降为原来的千分之一。

号段模式的三张王牌

一是趋势递增。号段按时间顺序发放,段内顺序用尽,整体随时间前进——正中 InnoDB 聚簇索引的下怀,B+ 树顺序追加,页分裂大幅减少。UUID 的三宗罪一消。

二是 ID 短小。bigint 8 字节,主键、二级索引、内存占用全回到舒适区。

三是自带容灾缓冲。内存里那段号没用完之前,就算 DB 整个挂了,发号服务还能继续撑一段——撑多久取决于 step,这个特性第 4 篇会被放大成核心设计。

三个缺点,条条要防

缺点一:号段有洞。服务重启或发号切换时,内存里没用完的号段直接作废,ID 序列出现空洞。对订单号来说空洞无害(只要求唯一不要求连续),但要在团队里讲清楚,别让运营拿「订单号不连续」当 bug 报。

缺点二:主从切换可能号回跳。这是最阴的一刀:发号表走主从复制,主库刚把 max_id 更新到 5000 还没来得及同步就宕机,从库提升为主后 max_id 还是 4000——新主继续发 4001 到 5000,和事故前的号段重叠,直接二次撞车。防线有几层:发号表不与业务库混部署,单独一套库减少切换;semi-sync 半同步复制把丢数窗口压到极小;应用层对已发号段做持久化记录,重启时跳过重叠区间。第 4 篇的双 buffer 会再给一道缓冲。

缺点三:多实例发号乱序但不失递增。两个发号实例交替领取号段时,A 领了 1-1000、B 领了 1001-2000,但业务请求先打到 B 时,早到的请求可能拿到更大的号——整体趋势向上,局部不严格有序。需要严格单调的场景(如按 ID 排序生成报表)要意识到这点。

号段与步长方案对比

维度步长方案号段模式
发号位置业务表自己独立发号表,业务解耦
扩容重排起点,停写对齐加一行 biz_tag 即可
DB 压力每单一次自增写每 step 次发号一次写
容灾DB 挂则发号停内存号段可撑一阵
多业务共用步长互相牵连一业务一行,天然隔离

小结

号段模式一句话:把发号从每单一次改成每段一次,DB 行锁保唯一,内存分发保吞吐,bigint 保短小。它是许多公司自研发号器的起点,美团 Leaf 的 segment 模式正是它的工程化版本。但它还差一口气:DB 一挂,内存段撑完就断供。下一步,把「撑一阵」放大成「从容切换」——双 buffer 与异步预加载,发号器的第一道高可用防线。

503

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

#分布式ID#号段模式#步长#发号器#Leaf

评论 (0)

相关推荐

连载中 12/20

排查四件套:jstack、jmap、jstat、jcmd 的实战分工

jstack 看线程在干什么,jmap 看堆里装了什么,jstat 看运行时在变什么,jcmd 是统一入口。四把刀各管一段,配合着用没有查不动的现场。

#jstack#jmap#jstat#jcmd#排查工具
2026-09-16 · 5 阅读 · 0 评论 · 0 赞
连载中 11/20

GC 日志:把回收过程翻译成人话

一行 GC 日志里塞着七种信息:谁触发的、收了哪、停了多久、活了哪些。加上 -Xlog 配置,再加上日志分析工具,GC 不再是只能盯监控曲线的黑盒。

#GC日志#Xlog#日志分析#GC监控#Full GC排查
2026-09-16 · 13 阅读 · 0 评论 · 0 赞
连载中 10/20

ZGC:亚毫秒停顿是怎么炼成的

百 G 大堆停顿不到一毫秒,靠的是把搬家全部挪到并发阶段——着色指针让引用自带状态,读屏障让搬运中的对象依然可访问。代价是吞吐与内存,收益是停顿与堆大小解耦。

#ZGC#着色指针#读屏障#亚毫秒停顿#分代ZGC
2026-09-15 · 8 阅读 · 0 评论 · 0 赞