【背景】 我带团队 3 年前做了一轮"异步化改造":把 12 个核心同步 RPC 调用(库存扣减、风控校验、积分发放、通知推送等)统一改成 MQ 消费。当时收益很明确——订单创建接口 P99 从 320ms 降到 85ms,QPS 上限从 1200 拉到 3400,DB 连接池从"天天打满"变成"偶尔告警"。
但 2 年后我们花了一整周修一个用户投诉量很大的 bug:用户在支付后 180~400ms 窗口内刷新页面,看到"已支付"但库存仍是"待扣减"状态。根因不是消息丢了,而是异步链路天然存在一个 200ms 量级的"不一致窗口",前端轮询间隔 500ms,恰好落在这个窗口里。
这不是个例。我后来统计了团队 14 个异步化操作,有 6 个的"最大不一致窗口"超过了产品预期,只是之前没触发投诉而已。
【常见分歧 / 几种做法】
- "全异步"派:一切非"用户必须当场拿到结果"的调用都走 MQ。同步只留给支付扣款、验证码校验这类"硬阻塞"。优点是 P99 好看、容量弹性大;缺点是"不一致窗口"被隐性转嫁给用户。
- "全同步 + 超时兜底"派:核心链路全部同步 RPC,MQ 只做审计日志和通知。优点是状态一致、排查简单;缺点是 P99 被最慢的下游拖死,一次下游 GC 就能把整条链路打爆。
- "混合 + 窗口预算"派:关键路径同步,非关键路径异步,但每个异步操作必须标注"最大不一致窗口"(ms 级),超过预算的要么改回同步、要么加补偿逻辑。
【我的倾向与理由】 我倾向第 3 种,核心规则只有一条:任何异步链路,必须在接口文档里写明"最大不一致窗口"(单位 ms),并且这个窗口要经过产品 / 前端确认。
具体落地步骤(我们团队后来固化为 checklist):
- 列出所有异步化操作,逐个标注"用户可感知的最大不一致时长";
- 和产品对齐哪些窗口可接受(我们定的是 200ms 以内可接受,超过必须有补偿);
- 对不可接受的,改回同步 RPC,或加"状态补偿"(如:消费方写一个
pending状态,前端轮询到pending时展示"处理中"而非旧值); - 给每个异步链路加一个
max_lag_ms指标(消费时间戳 - 生产时间戳),P99 超过预算就告警,而不是等用户投诉。
数字说话:改造后我们 14 个异步操作里,有 3 个被改回了同步(积分发放、风控强校验、库存预扣),11 个保留异步但加了 pending 状态 + 前端轮询兜底。用户投诉量从月均 40+ 降到个位数。
【想听大家聊聊】
- 你们团队的"异步化红线"是什么?是"用户能看到的页面"还是"核心交易链路"?
- 有没有踩过"异步化导致用户感知不一致"的坑?当时怎么定位、怎么修的?
- "最大不一致窗口"这个概念,你们有量化的指标吗?还是靠经验拍?
- 如果下游 P99 从 50ms 抖到 800ms(类似热榜那个扇出 5 下游的问题),同步链路直接超时、异步链路消息堆积——这两种"坏",你们哪个更怕?为什么?
欢迎带具体数字来聊,空谈"看场景"我接不住。
0赞
0收藏
0楼层