【背景】 做了 10 年后端,带过 30 人团队,管过日均 2 亿次调用的交易链路。最常被问的一个问题不是"怎么做到强一致",而是"这个接口到底需不需要强一致"。
举个例子:用户下单后,订单状态从"已创建"变"已支付",这个状态变更的可见性延迟,用户能接受 200ms 还是 2s?如果答案是 200ms,那你的读副本同步延迟必须压在 200ms 以内,否则用户看到"未支付"就会重复下单。但如果场景是后台报表,2s 甚至 30s 的延迟完全可接受。
问题是:这两个判断,在你团队里是怎么做出来的?有模型,还是拍脑袋?
【常见分歧 / 三种做法】 我见过三种典型路线,每种都翻过车:
1)"全强一致"派:所有读写都走主库。优点是简单、不出错;缺点是 P99 被主库的写锁和 redo log 拖累,单点压力大。某次我们团队就这么干,大促前 3 天压测发现主库 P99 从 15ms 飙到 120ms,全是 row lock 竞争,回滚方案直接废掉。
2)"全最终一致"派:能走从库就走从库,能异步就异步。性能数字很漂亮,但用户侧的"不一致窗口"变成事故——我见过一个团队,用户付完款 3 秒后刷新页面看到"未支付",一天接到 200 多个客服电话,资损对账又花了两周。
3)"按接口分级"派:核心交易链路(下单、支付、扣款)走强一致,辅助链路(商品浏览、订单列表、运营报表)走最终一致。这是多数团队的最终选择,但"分级"的粒度怎么定、谁拍板、怎么验收,往往没有共识,全靠架构师经验。
【我的倾向】 我倾向于把"一致性需求"当成一个可量化的 SLO 指标,而不是架构师拍脑袋的定性判断。具体做法:
- 每个对外接口定义一个 max_inconsistency_window(最大可接受不一致窗口),单位 ms,写进接口文档;
- 这个值不是技术团队单方面定的,而是和业务方一起推:用户侧感知到不一致后的重试率、投诉率、资损概率,反推出窗口上限。比如投诉率超过 0.1% 就触发告警,对应窗口就是告警阈值;
- 技术侧根据窗口选协议:200ms 以内 → 同步复制 + 主库读;2s 以内 → 半同步复制 + 读副本;30s 以内 → 异步复制 + 后台对账;
- 每季度故障复盘把"不一致窗口被突破"作为独立事件类型统计,不再混在"性能抖动"里。
好处是:技术选型有了客观依据。PM 问"为什么不走主库"时,你能拿出数据说"这个接口的一致性窗口是 30s,主库读只省了 8ms 但多扛了 40% 的写锁竞争",而不是"我觉得没必要"。
【想听大家怎么选】 所以想听听各位的真实经验,特别是有坑踩过的:
- 你们团队对"强一致 vs 最终一致"的决策,是有文档化的标准,还是 case-by-case 讨论?如果 case-by-case,决策者通常是技术 leader、架构师还是业务 PM?谁拍板?
- 有没有遇到过"业务方说不需要强一致,但用户投诉证明他需要"的情况?你们怎么回溯调整、怎么补数据?
- 对于 C 端用户直接可见的状态(订单状态、账户余额、库存扣减),你们的一致性窗口一般定在多少 ms?这个值是怎么算出来的,有没有反例?
- 你们有没有把"不一致率"(inconsistency rate)作为线上监控指标?怎么采样、怎么算、告警阈值设多少?
- 消息中间件(Kafka / RocketMQ)在这个"一致性预算"里扮演什么角色——是"一致性保证层"还是"纯传输管道"?你们团队怎么定位的?
我不觉得这个问题有标准答案,但我认为它应该有讨论——因为大多数团队在这个问题上不是"选择"的,而是"默认"的:默认强一致、默认最终一致、默认主从、默认异步。默认不是决策,而决策需要有人为它兜底。
欢迎带具体场景来聊,数字越具体越好。