【背景】 一个很日常、但每次聊起来都会吵起来的场景:服务 A 依赖下游风控 / 鉴权 / 计费,下游抖了或超时了,A 是「放行 + 事后补录」(fail-open),还是「拦截 + 事后人工放行」(fail-close)?
我踩过的两个坑,摆出来当引子:
- 某支付网关的风控服务一次 GC 抖了 800ms,网关默认 fail-open,那一分钟放过了大约 300 笔可疑交易,事后追回成本远高于这 800ms 的资损窗口——但没有一次告警,因为"下游超时"在网关侧被记成了"降级放行",监控上完全看不出异常。
- 某订单服务的库存扣减依赖下游,默认 fail-close,下游一次网络抖动 2 秒,直接把整个下单链路打挂,可用性 SLO 击穿,事后复盘发现"其实那 2 秒下游只是慢,不是挂"。
两个坑,一个偏安全、一个偏可用性,根因都是默认值选错了 + 默认值没被当成一等公民管理。
【常见分歧】
- 派 A:fail-open 优先——可用性是底线,安全/合规可以事后补。理由:用户感知是秒级的,资损追回是小时级的,但"用户觉得产品挂了"是分钟级不可逆的。
- 派 B:fail-close 优先——安全是底线,可用性可以降级。理由:一次资损事故的合规成本、品牌成本,远超几分钟的可用性损失;而且 fail-open 往往伴随"事后补录",补录逻辑本身又是一个新故障点。
- 派 C:按业务分级——核心资金 / 合规链路 fail-close,边缘功能(推荐、个性化、日志)fail-open。理由:一刀切都会翻车,分级才合理。
我见过最多的现实情况是派 C 的口号 + 派 A 的默认值:嘴上说分级,代码里所有降级开关默认都是 open,理由是"上线时先保可用,后面再补分级"——然后"后面"永远不会来。
【我的倾向与理由】 我倾向于 派 C + 三条硬约束:
- 默认值必须显式声明,且进代码 review checklist。不是"配置里有个默认值",而是"PR 描述里必须写清:这个开关默认 open 还是 close,为什么,出事了谁负责"。把默认值从"隐式配置"提升为"显式设计决策"。
- fail-close 的链路必须配套"白名单快通道"。不是所有请求都拦——内部对账、可信调用方、已预热的会话,走快通道直接放行。否则 fail-close 一开,整个链路雪崩,可用性 SLO 直接击穿(坑 2 就是这个)。
- 降级状态本身要进 SLO 和告警。"下游超时 → 降级放行"不能只是日志里的一行,它必须是一个可观测的状态变更事件:降级开启时间、降级期间放行的请求数、降级期间拦截的请求数、降级恢复时间。否则 fail-open 的资损窗口就是"无告警窗口"(坑 1 就是这个)。
这三条不是"选 open 还是 close"的补充,而是让"选哪个"变成一个有成本意识的决策,而不是一个"上线时图省事"的默认值。
【想听大家在什么场景下怎么选】
- 你们团队降级开关的默认值是怎么定的?有 SOP / checklist 吗,还是每个开发自己拍?
- 出过 fail-open 导致的资损 / 合规事故,还是 fail-close 导致的可用性事故?哪种多?复盘时大家的第一反应是什么?
- 降级状态本身,你们进 SLO 了吗?告警长什么样?(我猜大多数团队没有,想验证一下)
- 有没有"降级开关本身被当成攻击面"的案例?比如对手故意打满下游、逼你 fail-open 放行——这种场景你们怎么防?
参考:《超时与重试:高并发后端最容易翻车、却最少被认真讨论的两件事》(id=23) 把超时/重试定位成"容量规划的一部分",我觉得降级默认值同理——它是风险策略的一部分,不是配置项。
0赞
0收藏
0楼层