号段步长应该如何设置?
简化版
号段步长要同时覆盖峰值发号速率与中心故障恢复时间,并限制数据库申请频率和实例重启浪费。
可用 step ≥ peakQPS × desiredOfflineSeconds 给下界,再结合双 buffer、业务 key 热度和历史消耗动态调整;不能所有业务固定一个巨大步长。
详细版
某实例峰值 8000 ID/s,希望数据库故障时至少撑 60 秒,单 buffer 下界约 48 万,考虑安全系数可取 60 万;若双 buffer 都已准备好,可提供更长窗口。与此同时,低频业务每天只用 100 个 ID,60 万步长会产生巨大空洞,因此按 biz key 分档。
步长太小会频繁更新中心并增加切段 P99,太大则浪费、放大 max_id 跳跃并延长异常配置影响。动态策略基于最近峰值渐进升降,设最小/最大值和冷却期;已分配区间的步长变化不影响其所有权。
完整版教学
一、步长控制两种成本
小步长增加数据库事务、网络往返和切段次数;大步长增加宕机浪费、编号空洞和异常分配损失。设置步长就是在中心协调成本与本地库存成本之间取平衡。
记忆钩子:步长太小“老去仓库进货”,步长太大“仓库里全是用不完的货”。
二、从故障生存时间反推下界
step >= peakIssueRate × targetSurvivalTime
8000 ID/s × 60s = 480000 IDs
若加 25% 安全余量,可取 600000。这里使用峰值而不是平均值,并明确是单实例还是整个 biz key 的速率。双 buffer 只有 next 已成功加载时才能计入生存时间,不能默认总有两段。
三、从数据库容量反推另一条边界
10 个实例各 5000 ID/s,步长 1000 时总申请约 50 次/s;步长 100000 时约 0.5 次/s。中心数据库还要服务多少 biz key、主备复制和事务日志,决定可接受申请频率。
| 步长 | 单实例5000/s可用时间 | 10实例申请频率 |
|---|---|---|
| 1000 | 0.2s | 50/s |
| 10000 | 2s | 5/s |
| 100000 | 20s | 0.5/s |
四、低频业务不能照搬大步长
高频订单和低频后台任务共享 100 万步长,后者每次重启都可能浪费接近整段。可按历史 QPS 分小、中、大档,或存储每个 biz key 的动态 step。空洞若只是内部主键通常可接受,但外部票据连续性需求需另行设计。
极低频 key 甚至可以直接使用数据库自增/小段,不必为了统一架构缓存巨大范围。
五、动态调整要防振荡
根据上一段消耗时长调整:10 秒内用完可扩大 2 倍,超过 30 分钟可缩小一档;设置 stepMin、stepMax 和一次变更比例。使用 P95/P99 消耗速率,避免一个瞬时尖峰把步长永久拉大。
newStep = clamp(oldStep × factor, minStep, maxStep)
factor ∈ {0.5, 1, 2}
已领取的段按旧边界用完,新申请使用新 step,保证区间仍连续不重叠。
六、双 Buffer 与预取阈值
步长和预取时点要一起设计。数据库申请 P99 2 秒、峰值 8000/s,至少在剩余 16000 前发起;考虑重试和抖动,可在剩余 20% 或 time-to-exhaust 10 秒时预取,取更早者。
监控实际步长、段消耗时间、申请频率、浪费、预取失败和预计耗尽。配置变更先对单 biz key 灰度,避免所有实例同时申请新段。
七、常见误区与追问
- 误区:步长越大,性能一定越好。 中心压力下降后收益递减,浪费和风险继续上升。
- 误区:按平均 QPS 计算即可。 故障常与峰值叠加,应看峰值和安全系数。
- 误区:双 buffer 一定能撑两个完整步长。 next 申请失败时只有 current 余量。
- 误区:编号有空洞说明系统错误。 内部 ID 的空洞通常是安全丢弃段的正常代价。
- 追问:动态缩小会不会重复? 不会,中心始终从当前 max_id 向上分配不同长度区间。
- 追问:多个实例的步长按谁算? 按 biz key 总申请压力与单实例故障生存目标分别校验。
- 追问:预取阈值怎么定? 至少覆盖申请 P99、退避重试和峰值消耗时间。
八、加强记忆
步长由“峰值速率×想撑多久”给下界,由中心可承受申请频率校验,再用低频浪费约束上界。不同 biz key 分档,动态调整要有限幅和冷却;预取则用耗尽时间覆盖申请 P99。最终看的是故障生存时间,不是一个看起来很大的整数。