犯不着动用大炮的小场景
雪花和号段都搭好了,老王又接了个小需求:运营要给活动发一批优惠券码,量级每天几万;下个月还有短链服务,也是类似的量。为这点流量再部署一套发号服务,杀鸡用牛刀。他的目光落到公司现成的 Redis 上:INCR 原子自增,一行命令一个号,就这么简单?
真就这么简单,但简单背后有两本账要算清——持久化账和可用性账。算不清,简单方案会在某天变成撞号事故。
INCR 为什么能发号
Redis 命令处理是单线程的,INCR 对同一个 key 的自增天然串行——一万个客户端同时 INCR,拿回的是一万个不同数字,原子性由 Redis 单线程模型白送,连锁都不用写:
INCR coupon_seq 返回 1, 2, 3 ... 一次一个号
INCRBY coupon_seq 1000 返回 60000,本次领走 59001-60000 的千号段第二行是进阶玩法:Redis 也能玩号段。INCRBY 一次领千号,内存分发,DB 号段模式的思路原样平移,还省去了 DB 行锁——单线程本身就是全局锁。网络往返次数从每号一次降到每千号一次,吞吐轻松上百万。
第一本账:持久化,号会跳不能回
Redis 的号存在内存里,持久化策略决定宕机后号码的成色。核心原则先立好:号有洞能忍,号有重不能忍——洞只是难看,重是真资损。
| 持久化策略 | 宕机后号码成色 | 风险 |
|---|---|---|
| RDB 快照 | 回跳到上次快照点 | 快照后的号全部重发,事故级 |
| AOF everysec | 最多丢一秒的号 | 丢的号成洞,可接受 |
| AOF always | 基本不丢 | 每次写盘,吞吐掉一个量级 |
结论清晰:发号专用实例必须 AOF everysec 起步,容忍丢号(洞)换性能;RDB-only 的实例绝不能碰发号。要是业务极端不能容忍重号又受不了 always 的性能,那 Redis 就不是正确的战场——回退到 DB 号段。
第二本账:主从切换,号会回
Redis 主从复制是异步的:主库 INCR 到 60000,还没同步给从库就宕机,哨兵把从库提主——新主的计数器可能停在 58000,接下来发出的号与事故前的 58001-60000 重叠。这是和 DB 号段「主从切换号回跳」(第 3 篇)同款的病,药方也同款:
一,发号专用实例,不和缓存业务混部,切换策略与监控独立;二,应用侧记水位——每次领号段把 max 落地到本机或另一存储,Redis 恢复后对账跳过重叠区间;三,redis 挂了别死等,降级路线(第 14 篇)要提前铺。记住第 8 篇 workerID 的 Redis 方案同款风险——凡是「自增计数器当真源」的地方,主从回跳都是头号假想敌。
Redis 号段与 DB 号段对比
| 维度 | DB 号段 | Redis 号段 |
|---|---|---|
| 单号延迟 | 毫秒级(DB 事务) | 亚毫秒 |
| 持久化保证 | 事务落盘,强 | AOF 策略决定,可调 |
| 主从切换风险 | 半同步可控 | 异步复制有回跳窗口 |
| 运维心智 | DB 团队熟 | 轻,但持久化配置要专项盯 |
适用与不适用
老王的落地结论:短链码、券码、活动序列号这类允许洞、量级中小、无强审计诉求的 ID,Redis 号段是真香方案——一行 INCRBY 加一个双 buffer 包装就上线。订单主键、资金流水这类资损敏感的 ID,仍然留给 DB 号段或雪花——简单是有价格的,价格就是上面两本账。
小结
Redis 发号一句话:单线程白送原子性,INCRBY 平移号段模式;AOF 管号不重,水位对账防回跳,资损敏感的场景别贪便宜。至此四大发号路线(UUID、号段、雪花、Redis)全部讲完,怎么选?下一篇把开源实现摆上桌,一张决策树一锤定音。
评论 (0)