Leaf 号段快取完时 DB 抖了 200ms,发号 RT 从 1ms 拉到 1.2s:雪花、号段、Leaf 的 3 个发号瓶颈
title: Leaf 号段快取完时 DB 抖了 200ms发号 RT 从 1ms 拉到 1.2s雪花、号段、Leaf 的 3 个发号瓶颈date: 2026-08-22category: 分布式IDtags: [Java, 后端, 分布式ID, 架构]我们的订单号、物流单号、支付流水号都来自一个统一的发号服务。早期用雪花算法上容器后踩了一脚 workerId 冲突的坑那次订单表主键报了 3000 次 Duplicate后来切到号段模式。但号段模式也不是银弹——有次 DB 慢查询把发号 RT 从 1ms 直接拉到 1.2s拖慢了整条下单链路。这篇把雪花、号段、Leaf 三种方案的真实瓶颈拆开尤其是号段模式的「双 buffer」到底解决什么、又留下什么坑。雪花容器化下 workerId 怎么来是第一个雷雪花 ID 由「时间戳 workerId 序列号」组成。单机时代 workerId 写死在配置里没问题容器化后 Pod 频繁重建、IP 漂移写死的 workerId 很容易撞车。// 雪花算法核心简化同一毫秒内靠 sequence 区分靠 workerId 区分机器 public synchronized long nextId() { long timestamp timeGen(); if (timestamp lastTimestamp) { throw new RuntimeException(时钟回拨); } if (timestamp lastTimestamp) { sequence (sequence 1) SEQUENCE_MASK; if (sequence 0) { timestamp tillNextMillis(lastTimestamp); // 本毫秒序号用尽等下一毫秒 } } else { sequence 0; } lastTimestamp timestamp; // 41 位时间戳 | 10 位 workerId | 12 位序列号 return (timestamp 22) | (workerId 12) | sequence; }踩坑点逐个说workerId必须全局唯一。我们用过「IP 末段取模 1024」生成结果两个 Pod 恰好拿到相同 IP 段workerId 撞了同一毫秒不同机器的 ID 完全相同订单表主键冲突。时钟回拨直接抛异常。K8s 节点 NTP 校准时偶尔回拨几百毫秒那几秒发号全失败。我们最后改成「回拨小于 5ms 就自旋等大于 5ms 才报警」而不是一刀切抛异常。序列号只有 12 位4096/毫秒高并发下单一个 worker 每秒上限约 409 万。对单实例够用但多实例聚合时被 workerId 位数10 位限制了机器规模。雪花还有一个常被忽略的软限制41 位时间戳大约能用 69 年从 1970 算起而且它依赖「相对某个 epoch 的偏移」。我们曾经有人把 epoch 设成了系统启动时间结果每次重启时间归零、ID 可能重复后来统一用2020-01-01作为固定 epoch 才稳住。号段模式不在 ID 里编码机器靠 DB 批量发号号段模式的思想完全不一样不去算 ID而是向 DB 申请一段区间比如 [1, 1000]内存里慢慢发发完再申请下一段。// 号段模式从 DB 取一段号本地自增发放 public class SegmentIdGenerator { private volatile long current; private volatile long max; // 当前段最大值 public synchronized long nextId() { if (current max) { // 当前段用完去 DB 取下一段并更新 max Segment seg fetchNextSegmentFromDb(); current seg.start; max seg.end; } return current; } }号段模式的好处是ID 里不带机器信息纯递增、可读、好排障。但瓶颈也明显每次「跨段」都要打一次 DB。如果 DB 慢跨段那一刻的 RT 直接挂到 DB 那边。我们那次 1.2s 的 RT就是因为号段临界点正好撞上 DB 一次慢查询。号段表的设计也很关键我们用的是类似 Leaf 的结构CREATE TABLE id_segment ( biz_tag VARCHAR(64) PRIMARY KEY, -- 业务标识如 order/pay/logistic max_id BIGINT NOT NULL, -- 当前已分配到的 ID step INT NOT NULL, -- 每次取的长度 version BIGINT NOT NULL -- 乐观锁防并发取段冲突 ); -- 取段用一句原子更新UPDATE id_segment SET max_id max_id step WHERE biz_tag?step就是「一次取多长」。step 太小跨段频繁DB 压力大step 太大服务重启会浪费一段 ID内存里没发完的段丢了。我们最后按业务峰值估算把 order 的 step 设到 10 万。Leaf 的双 buffer把「跨段卡顿」藏起来美团 Leaf 的号段模式做了个关键优化——双 buffer不等当前段用完才去取而是在用到一定比例比如 10%时就异步把下一段预取好。// Leaf 双 buffer 思路简化 class SegmentBuffer { Segment[] segments new Segment[2]; // 两个段一个在用一个备用 int currentPos 0; volatile boolean nextReady false; public long nextId() { Segment cur segments[currentPos]; long id cur.nextId(); // 用到 10% 且备用段还没在加载触发异步预取 if (cur.idleRatio() 0.1 !nextReady) { asyncLoadNextSegment(); } // 当前段用尽且备用段已就绪切换 if (cur.isOver() nextReady) { currentPos ^ 1; nextReady false; } return id; } }这个设计解决了号段模式的「临界卡顿」大部分请求命中内存里的段只有第一次取段和异步预取失败才会真的等 DB。但我们那次 DB 抖 200ms 时正好异步预取也跟着慢了buffer 切换的瞬间还是被拖了一下——双 buffer 降低的是「常规跨段」的延迟扛不住的是「DB 整体变慢」。Leaf 的高可用与号段监控号段模式把发号服务的可用性很大程度上交给了 DB所以高可用设计不能省。我们做了三件事号段表独立库 只读从库做预取源。主库只负责UPDATE ... SET max_id max_id step这一行原子更新预取读走从库主库压力极小。号段剩余告警。监控每个 biz_tag 的「当前 max_id - 已发放」比例低于 20% 就告警避免段耗尽又没及时取新段导致发号失败。多节点共享同一张段表 乐观锁 version。多个发号服务实例并发取段时靠UPDATE ... WHERE version ?防冲突谁更新成功谁拿到新段天然支持水平扩展。-- 取段是原子的CAS 式更新失败就重试 UPDATE id_segment SET max_id max_id 100000, version version 1 WHERE biz_tag order AND version 42;这套下来发号服务的 SLA 从「依赖单库」变成了「依赖 DB 主从 本地内存 buffer」单库抖动基本被双 buffer 吸收只有主库整体不可用才会影响发号。代价是架构多了一个要重点保障的 DB 组件——和雪花「依赖时钟」、Kafka「依赖 broker」一样没有哪种方案是零依赖的。另外补充一个细节号段模式重启会丢当前内存段里没发完的号所以 step 越大、重启浪费越多。我们按「单实例 1 分钟能发完的量」估 step既避免频繁跨段又把重启浪费控制在可接受范围。上线这套结构后半年发号服务经历了 3 次 DB 主库抖动、1 次从库延迟业务侧发号 RT 全程无感知SLA 维持在 99.99%这也反过来印证了「双 buffer 独立库」组合的有效性。三种方案对比看瓶颈在哪方案ID 是否递增依赖典型瓶颈雪花时间趋势递增机器时钟workerId 分配、时钟回拨号段严格递增DB 一段跨段打 DB 的 RTLeaf 双 buffer严格递增DB 一段 异步预取DB 整体变慢时预取延迟我的取舍如果你的 ID不需要连续递增、又跑在容器里别用裸雪花workerId 分配和时钟回拨够你喝一壶。要么上号段要么用「ZooKeeper/Redis 注册 workerId」的雪花变体。号段/Leaf 适合「ID 要可读、要递增、要好排查」的业务订单号、流水号但DB 必须稳。我们把号段表单独建库、配上只读从库做预取数据源DB 抖动对发号的影响降到了可忽略。号段有个常被忽略的点段要设得够大。我们早期一段只设 100结果高并发下每秒跨段几十次DB 压力反而比预期大调到 10 万一段后跨段频率降到几分钟一次DB 几乎没压力。复盘数字切到 Leaf 双 buffer 后发号 P99 从雪花的「时钟回拨时直接失败」变成稳定在 2ms 以内常规情况下跨段完全无感。那次 1.2s 的 RT 事故根因是号段表和业务库混在一个实例上业务高峰把 DB 连接占满预取 SQL 排队。把号段表迁到独立实例并设段大小 10 万后连续 3 个月发号 RT 全程低于 5msDB 慢查询零相关告警。上线半年发号服务支撑了日均 1.2 亿次调用零重复 ID。思考题号段模式 ID 严格递增这既是优点好排查也是缺点容易被竞争对手通过订单号推算你的日单量。如果你的业务既想要「不暴露规模」又想要「不依赖机器时钟」你会怎么改号段模式

相关新闻

详解AUTOSAR:专栏总述

详解AUTOSAR:专栏总述

目录 1、理论篇 2、工具篇 3、环境配置篇 4、实践篇 5、项目篇 6、拓展篇 本专栏主要介绍汽车嵌入式系统软件规范AUTOSAR以及符合AUTOSAR规范的车用控制器软件开发方法。 在编写过程中尽可能以通俗易懂的语言和形象的图解来展现AUTOSAR中一些复杂的概念问题,…

2026/8/22 16:15:32 阅读更多 →
spring boot 连接emqx并实现发布订阅

spring boot 连接emqx并实现发布订阅

1、安装依赖 <dependency><groupId>org.springframework.integration</groupId><artifactId>spring-integration-mqtt</artifactId><version>7.1.0</version><scope>compile</scope></dependency><!-- Source:…

2026/8/22 16:15:32 阅读更多 →
运维手动改了一行数据,Seata 回滚时把它覆盖了:AT 模式全局锁和 undo_log 的 3 个被忽略的边界

运维手动改了一行数据,Seata 回滚时把它覆盖了:AT 模式全局锁和 undo_log 的 3 个被忽略的边界

title: 运维手动改了一行数据&#xff0c;Seata 回滚时把它覆盖了&#xff1a;AT 模式全局锁和 undo_log 的 3 个被忽略的边界 date: 2026-08-22 category: 分布式事务 tags: [Java, 后端, 分布式事务, Seata, 微服务]我们订单和库存两个服务用 Seata AT 模式做分布式事务。AT …

2026/8/22 16:15:32 阅读更多 →

最新新闻

链上协议设计的边界比较

链上协议设计的边界比较

链上协议设计的边界比较 把以太坊&#xff08;EVM 生态&#xff09;上的 DeFi 协议设计思路直接套到 Solana 生态&#xff0c;或者拿 Solana 高并发交易的经验去评估 EVM 链上的清算协议&#xff0c;往往会得出错误的结论。 以太坊和 Solana 在底层状态机、内存池机制&#xff…

2026/8/22 19:08:36 阅读更多 →
把我们刚才完成的全部流程打包成一个 Skill(技能包)

把我们刚才完成的全部流程打包成一个 Skill(技能包)

Package everything we just did into a skill.翻译&#xff1a;把我们刚才完成的全部流程打包成一个 Skill&#xff08;技能包&#xff09;Claude工作原理&#xff08;Claude Code / Agent Skills&#xff09;这句话是 Claude Code 里非常经典的提示词&#xff1a;在当前对话里…

2026/8/22 19:08:36 阅读更多 →
接口解析层的常见性能误区

接口解析层的常见性能误区

接口解析层的常见性能误区 在 Node.js 中搭建 GraphQL API 服务&#xff0c;不少团队刚上手时觉得体验极佳&#xff1a;前端想要什么字段就传什么字段&#xff0c;几行代码就能把现有 REST API 或数据库打包暴露出去。 然而&#xff0c;随着系统规模扩大&#xff0c;N1 查询死锁…

2026/8/22 19:08:36 阅读更多 →
开源数据恢复:三步找回分区与误删文件

开源数据恢复:三步找回分区与误删文件

开源数据恢复&#xff1a;三步找回分区与误删文件 【免费下载链接】testdisk TestDisk & PhotoRec 项目地址: https://gitcode.com/gh_mirrors/te/testdisk 凌晨三点&#xff0c;你在装双系统&#xff0c;安装器里刚把一块还存着数据的分区删了——点下去那一秒你就…

2026/8/22 19:08:36 阅读更多 →
MMD Tools 新手操作指南:五分钟跑通 PMX 模型与 VMD 动作的 Blender 完整流程

MMD Tools 新手操作指南:五分钟跑通 PMX 模型与 VMD 动作的 Blender 完整流程

MMD Tools 新手操作指南&#xff1a;五分钟跑通 PMX 模型与 VMD 动作的 Blender 完整流程 【免费下载链接】blender_mmd_tools MMD Tools is a Blender addon for importing/exporting Models and Motions of MikuMikuDance. 项目地址: https://gitcode.com/gh_mirrors/bl/bl…

2026/8/22 19:08:36 阅读更多 →
从集合论到并发控制:重叠问题的本质与工程实践

从集合论到并发控制:重叠问题的本质与工程实践

你有没有遇到过这样的场景&#xff1a;一个看似简单的任务&#xff0c;比如整理文件、处理数据或者安排日程&#xff0c;当你开始动手时&#xff0c;却发现事情像一团乱麻&#xff0c;相互交织&#xff0c;理不清头绪。你尝试一件一件处理&#xff0c;却发现A任务还没做完&…

2026/8/22 19:07:36 阅读更多 →

日新闻

沉金PCB工艺实战指南:从设计到SMT焊接的可靠性保障

沉金PCB工艺实战指南:从设计到SMT焊接的可靠性保障

在电子硬件开发领域&#xff0c;PCB&#xff08;印制电路板&#xff09;的沉金工艺是提升产品可靠性和焊接质量的关键环节。对于需要高密度互连、长期稳定运行或高频信号传输的板卡&#xff0c;如“黍姐仿通行证”这类可能涉及身份识别、数据交互的硬件项目&#xff0c;选择正确…

2026/8/22 0:00:11 阅读更多 →
电气考研电路八月强化四步法:从知识体系到真题实战的闭环攻略

电气考研电路八月强化四步法:从知识体系到真题实战的闭环攻略

这次我们来看一个针对电气考研电路科目的学习规划项目。它不是软件工具&#xff0c;而是一套聚焦于8月份关键节点的备考策略。对于电气工程考研的同学来说&#xff0c;电路分析是专业课的重中之重&#xff0c;也是拉开分差的关键。进入8月&#xff0c;复习进入强化阶段&#xf…

2026/8/22 0:00:11 阅读更多 →
消除AI代码的“AI味”:Claude Code设计优化技能配置与实战指南

消除AI代码的“AI味”:Claude Code设计优化技能配置与实战指南

大家好&#xff0c;我是专注于前端开发与AI工具实践的技术博主。在日常使用 Claude Code 等AI编程助手时&#xff0c;你是否也遇到过这样的困扰&#xff1a;生成的代码功能上没问题&#xff0c;但代码风格、组件设计、交互逻辑总透着一股“AI味”——布局单调、样式简陋、交互生…

2026/8/22 0:00:11 阅读更多 →

周新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者&#xff0c;最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent&#xff0c;从本地部署到云端API&#xff0c;我们正处在一个技术栈快速重构的节点。然而&#xff0c;面对层出不穷的模型、框架和工具&#xf…

2026/8/21 3:21:33 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/22 8:09:09 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室&#x1f447; 关注我领取海量matlab电子书和…

2026/8/21 6:07:56 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速&#xff1a;macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/22 18:08:39 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南&#xff1a;3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗&#xff1f;ncmdump解密工具帮你轻松解决这个困…

2026/8/22 7:31:03 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片&#xff1a;为英语学习 App 打造桌面级学习助手适用平台&#xff1a;HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0&#xff08;API 26 Beta&#xff09;新增了 AgentCard 智能体卡片能力&#xff0c;这是继 HMAF&#xff08;鸿蒙智能体框架&#x…

2026/8/22 3:22:48 阅读更多 →