连载中 15/16

踩坑实录:前十四篇没写透的七个坑

2026-06-12 · 7319 阅读 · 0 评论 · 0 赞

事故清单摊开看

前十四篇把主干讲完了,但老王复盘半年的工单发现,真正把人逼疯的往往是边角料:不是架构选错,而是位数算错、类型选错、约定没写下来。他把这些坑列成清单,一共七条,条条都流过血。逐条过。

坑一:JS 精度丢失,尾号集体变 0

现象:前端反馈订单详情查不到,抓包一看,后端返回的雪花 ID 尾部好几位变成了 0,而数据库里明明是正常数字。排查半天 Java 日志——后端发的号是对的,问题出在浏览器:JavaScript 的 Number 是 IEEE 754 双精度浮点,安全整数范围只有 2 的 53 次方减一,而 64 位雪花 ID 轻松越线,超出部分被静默舍入——尾号丢精度,详情接口自然对不上。

解法:序列化时把 Long 型 ID 统一转字符串返回(Jackson 配置 Long 序列化为 String,或全局加一层转换)。这条要写进团队规范——凡是超过 53 位整数语义的字段,出网一律字符串。名字都别叫 number,叫 string。

坑二:秒级时间戳的八年之约

现象:接手别人项目,UidGenerator 秒级时间戳 28 位,算了一下距号耗尽只剩不到三年——上一任规划时按「当前时间 + 8.5 年」倒推,规划完两年没人记得这茬。

解法:位数分配表必须写进代码注释与运维文档,并把「ID 耗尽日」当成一个监控指标(按当前消耗速率动态预估)。改造方案提前一年排期:要么时间位扩位(序列位缩位换),要么换发号方案。耗尽不是某天的突发事件,是每天逼近一天的既定事实——把它变成看得见的倒计时。

坑三:纪元起点用了默认值

现象:雪花的时间位是从「纪元起点」开始计的偏移量。图省事直接用了库默认起点(比如 2010 年),白白烧掉十几年时间位——等于人生下来就从 35 岁开始算退休倒计时。

解法:纪元起点自定义成项目上线日附近,一分时间位都不浪费。同时警告:纪元一旦定下不能改——换了起点,全体历史 ID 的时间语义整体漂移,按时间范围查数据的逻辑全炸。纪元和分片基因一样,属于「焊死」决策,进架构决策记录。

坑四:号段长度的心理战

现象:小业务团队为了「ID 好看」把 step 设成 100,高峰期一分钟取十几次号段,DB 被打挂;另一极端设成 1000 万,应用重启一次就烧掉一千万个号,量大业务一年浪费的号比存量还多。

解法:step 是「DB 压力」与「浪费与洞」的杠杆,默认值建议按 峰值 QPS × 10 秒到 60 秒的量估——buffer 里常备十秒到一分钟的号,DB 每分钟最多被每实例打扰几次。有条件的上动态 step(Leaf 的思路),让系统自己找平衡。

坑五:workerID 没带机房维度

现象:同城双机房上线三个月相安无事,直到老王做单元化改造把两地同时切主——两地各有一台 workerID=7 的机器,同一毫秒发出同一个 ID。第 8 篇的分配表是按单机房规划的,机房维度压根没留。

解法:workerID 位一拆为二:高位做机房号(dataCenterID),低位做机器号。哪怕暂时单机房,也要在位分配里预留这个维度——位分配是十年合约,机房是迟早的事。

坑六:把 ID 当业务字段解析

现象:有业务方发现订单 ID 尾号是基因位,直接在代码里写死「ID 后 8 位取模定位库表」,绕过分片中间件。半年后位分配调整,所有硬编码解析的地方集体报错。

解法ID 的位语义只属于发号器,对外只承诺「唯一 + 趋势递增」两条,位级别的解析必须收敛到统一的工具类(分片算法内部),别处一律当黑盒。谁解析谁负责——这规矩要写进 code review 清单。

坑七:序列位塞私货

现象:有同学脑洞大开,把渠道号塞进序列位高位「省一次字段存储」,单机自增没问题,一到多机并发——序列位被私货占掉几位,单毫秒容量从 4096 掉到 256,高峰期大量自旋等待;更要命的是两个渠道塞了同一个值,唯一性靠运气。

解法:序列位是唯一性的生命线,纯净保留,禁止复用。业务信息想跟 ID 走,要么走第 12 篇的外部 ID 映射(外部单号里随便编),要么老老实实存字段。

小结

七坑一表收尾:出网转字符串防精度丢失,倒计时监控防号耗尽,纪元焊死防语义漂移,step 按峰值估防两头挨打,workerID 留机房位防多活撞号,位解析收敛防硬编码,序列位保纯净防唯一性破功。每一条都不是高深技术,是纪律。主干加边角都补齐了,下一篇收官——把十六篇串成一张作战地图。

503

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

#分布式ID#踩坑#JS精度#号段长度#workerID

评论 (0)

相关推荐

连载中 12/20

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

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

#jstack#jmap#jstat#jcmd#排查工具
2026-09-16 · 4 阅读 · 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 赞