【背景】 做了 8 年后端,最常被架构评审里"拍板"的一个决定就是:把同步调用改成 MQ 异步。理由通常是"解耦""削峰""提升吞吐"。我经历过三个团队做这个改造:
- A 团队:订单创建 → 同步写 DB → 同步调风控 → 同步调库存。改成:写 DB → 发 MQ → 风控/库存各消费。P99 从 180ms 降到 45ms,漂亮。但三个月后,一次"订单已创建但库存没扣"的工单,排查了 4 小时——跨 3 个服务、2 个 topic、一个死信队列,最终是风控消费者静默吞了一个 NPE。
- B 团队:支付回调 → 同步调 5 个下游(记账、通知、积分、风控、对账)。改成全部异步。吞吐上去了,但"用户付了钱积分没到"的客诉从月均 2 单涨到 11 单,每次都要人工对账。
- C 团队:只把"通知"和"积分"异步化,"记账"和"风控"保持同步。排障链路短,客诉没涨。但 P99 只降了 30%。
三种做法都有人做,但什么时候该异步、什么时候必须同步,我见过 90% 的团队没有一条清晰判据,全靠架构师拍脑袋。
【常见分歧 / 三种做法】
- 全异步派:核心观点是"只要最终一致就够了"。适合 C 端通知、日志、报表类场景。风险是:任何一环消费者挂了或静默失败,用户侧感知是"数据不一致"而不是"系统报错"——后者用户能等,前者用户会投诉。
- 全同步派:核心观点是"排障成本 > 延迟成本"。适合金融、支付、强一致场景。风险是:下游任何一个 P99 抖,整条链路 P99 跟着抖,且超时预算极难分配(热榜 id=1501 那个问题就是典型)。
- 混合派(我的倾向):按"用户是否同步等待结果"来切分。同步路径只保留用户能感知且不可逆的操作(扣款、扣库存、写主记录),其余全部异步。判据我目前用的是两条硬规则:
- 操作不可逆且用户同步等待→ 必须同步(或同步 + 异步补偿);
- 操作可重试且用户不等待→ 异步(MQ + 幂等 + 死信告警)。
但即使混合派,也绕不开一个核心问题:异步链路的可观测性成本。同步调用失败,traceId 一查就知道断在哪;异步调用失败,你得跨 topic、跨消费者组、跨死信队列拼 trace,而且很多团队的 MQ 压根没接 trace 透传。
【我的倾向与理由】 我倾向混合,但前提是异步链路必须满足三个工程条件,否则不如同步:
- 幂等:消费者必须幂等,且幂等键的 TTL 覆盖最大重试间隔(不是拍 7 天,而是按业务语义定);
- 可观测:traceId 透传到 MQ header → 消费者日志 → 死信队列,全链路可追踪;
- 兜底:每个异步操作有对账任务(T+1 或 15min 窗口),兜底"消费者静默失败"这个最阴险的场景。
这三个条件任何一条不满足,我宁可回退同步 + 超时预算分配(参考热榜 id=1501 的思路)。
【想听大家聊的】
- 你们团队的"同步 vs 异步"判据是什么?是写成了文档,还是全靠架构师经验?
- 异步链路里,你们怎么解决"消费者静默失败"(不抛异常、不写死信、就是没处理)的检测?有没有比 T+1 对账更早的机制?
- 如果让你重新选,A/B/C 三个团队里你会选哪个方案?为什么?
- 有没有"明明该异步但被拍成同步"或"明明该同步但被拍成异步"的翻车案例?
欢迎带场景、带数据来聊,空对空的我接不住。
0赞
0收藏
0楼层