把工具箱摆上工作台
前 17 篇的知识点像散落的零件,这一篇装成四台机器。每个场景都标注用到了哪些技术,方便哪天照方抓药。
场景一:订单超时关闭(延迟消息三保险)
用到:第 9 篇延迟消息、第 7 篇状态机、第 12 篇兜底思维。
- 第一保险:下单成功发 30 分钟延迟消息,消费者到点检查并关单;
- 第二保险:关单动作走状态机(仅待支付可关),与支付回调的竞态天然安全;
- 第三保险:每日凌晨扫表对账,捞出漏网之鱼(延迟消息丢失、消费失败的极小概率事件)。
三层防线各司其职:延迟消息管准时,状态机管竞态,对账管万一。
场景二:秒杀下单(削峰的正确姿势)
用到:第 1 篇削峰、第 12 篇容量规划。
用户请求 -> 网关限流(只放 1 万 QPS) -> Redis 预扣库存(Lua 原子扣减)
-> 扣减成功发 MQ -> 消费者慢慢落库、生成订单、发起支付关键设计:库存预扣在 MQ 之前完成,Redis 原子扣减挡住超卖,MQ 只接住已扣减成功的单。反过来先入队再在消费端扣库存,洪水会全部灌进队列,消费端扣不过来照样超卖。队列在这里的职责是「让落库和支付链路匀速工作」,用户端则拿到「排队中」的友好等待页。
场景三:数据同步(binlog 订阅式)
用到:第 4 篇核心模型、第 8 篇顺序、第 7 篇幂等。
需求:订单库变更要实时同步到 Elasticsearch 和缓存。业务代码双写(写库后手动发消息)看似简单,实则埋雷:写库成功发消息失败、双写的代码每个业务方都要写一遍。工程正解是 Canal 订阅 binlog:
MySQL binlog -> Canal(伪装成从库) -> MQ(表名+主键做 key 保序)
-> 同步消费者 -> ES upsert(幂等)/ 缓存删除业务方零改动,binlog 天然可靠(与 MySQL 复制同源)。同步端三个要点:表名+主键做 key 路由保证同一行有序(第 8 篇);目标端用 upsert 幂等(第 7 篇);全量初始化与增量同步的衔接用「先全量打标,再切增量」。
场景四:支付回调的最终一致
用到:第 5 篇本地消息表、第 10 篇事务消息、第 11 篇重试。
支付渠道回调处理「标记订单已支付 + 通知履约」。标记是本地事务,通知走 MQ。用事务消息(或本地消息表)保证「标记成功则通知必达」,履约服务消费失败自动重试 16 次,死信告警人工兜底。再加每日对账任务:拉取渠道账单,逐单与本地支付流水核对,金额或状态不平的自动生成差错单——对账是最终一致的最后一道闸。
四场景的技术地图
| 场景 | MQ 扮演的角色 | 关键技术 |
|---|---|---|
| 订单超时 | 延迟提醒器 | 延迟消息、状态机、扫表对账 |
| 秒杀 | 蓄水池 | Redis 预扣、削峰、容量规划 |
| 数据同步 | 传输管道 | binlog 订阅、key 保序、upsert 幂等 |
| 支付回调 | 可靠性传动轴 | 事务消息、重试、死信、对账 |
小结
四个场景一个共性:MQ 从来不是孤军,它和状态机、幂等、对账、限流组队上场。单点技术解决不了业务问题,组合拳才解决。
下一篇是出发前的最后一次安检:陷阱清单——丢失、重复、乱序、积压的一线事故复盘合集,看看别人踩过的坑长什么样。
评论 (0)