降级数据应该如何设计?
简化版
降级数据必须“可识别、可过期、不越权、不伪造核心事实”。它可以是旧缓存、静态配置、裁剪结果或明确的不可用响应,但不能用看似正常的默认值掩盖未知状态。 设计时同时定义来源、最大陈旧时间、适用人群、响应标记、缓存隔离和恢复后的清理方式。
详细版
先按业务语义选 fallback:推荐可用热门榜单,商品描述可用最近缓存,库存和余额未知则应明确失败或只读,不能返回 0 或“充足”。响应携带 degraded、dataAsOf 和原因码,使客户端、日志与指标都能区分正常结果。
降级缓存要与正常缓存分 key 或带版本,设置更短 TTL,避免回源恢复后旧值继续命中。含用户权限、价格和地域规则的数据必须在相同上下文下生成,严禁跨租户复用。策略还需通过过期、越权、恢复和客户端兼容测试。
完整版教学
一、fallback 不是随便填默认值
当依赖不可用时,系统仍要对用户诚实。推荐列表为空通常只是体验下降,而余额返回 0 会让用户误以为资金消失,库存返回 999 则可能导致超卖。选择降级数据的第一原则是:替代结果不能改变关键业务决策。
易错点:技术上的“请求成功”不等于业务上的“结果可信”,降级必须显式暴露质量变化。
二、四种常见来源
| 来源 | 优点 | 风险 | 合适场景 |
|---|---|---|---|
| 最近缓存 | 接近真实值 | 数据陈旧 | 商品描述、榜单 |
| 静态兜底 | 稳定、无依赖 | 个性化差 | 导航、推荐 |
| 裁剪结果 | 保留核心字段 | 客户端兼容 | 详情页非关键模块 |
| 明确不可用 | 语义最诚实 | 体验中断 | 余额、支付、库存未知 |
旧数据是否可用取决于业务的新鲜度预算,而不是“缓存里有就返回”。昨日的文章榜单可能可接受,昨日的机票价格通常不可接受。
三、用数据时间界定陈旧度
为每类数据定义 maxStaleness。例如商品描述允许 24 小时,会员等级允许 5 分钟,库存不允许陈旧读。若缓存生成于 10:00、当前 10:08,而会员等级预算是 5 分钟,就必须拒绝使用,即使缓存尚未到技术 TTL。
usable = now - dataAsOf <= maxStaleness
10:08 - 10:00 = 8min > 5min => 不可作为会员等级兜底
技术 TTL 控制存储生命周期,业务陈旧度控制能否对外使用;两者不能混为一个参数。
四、响应契约要让调用方看见降级
可以保留原有数据结构,同时增加向后兼容的元信息。旧客户端忽略新字段仍能渲染,新客户端则可显示“数据更新中”并禁止依赖高精度数据的操作。
{
"data": {"rank": ["A", "B", "C"]},
"degraded": true,
"fallbackType": "STATIC_RANKING",
"dataAsOf": "2026-09-29T00:00:00Z"
}
HTTP 200 是否合适取决于接口契约,但监控绝不能把降级命中混进正常成功率。
五、隔离缓存污染与权限泄漏
正常结果和降级结果共用 key 时,fallback 可能被写入长 TTL 缓存,依赖恢复后仍服务旧值。可使用 normal: 与 fallback: 命名空间,或写入质量等级并让读取优先正常版本。恢复时主动失效降级缓存,且禁止降级响应反向覆盖源数据。
用户数据还要保留租户、地域、会员等级和权限维度。为节省空间把 A 租户的旧权限列表给 B 租户使用,是严重越权,不是可接受降级。
六、数字化容量与恢复验证
假设依赖平时 2000 QPS,静态 fallback 由本地内存提供,预计仅消耗正常 CPU 的 10%。故障演练要验证切换后实例仍能承受 2000 QPS、降级率接近 100%,而不是 fallback 又去查询同一个故障数据库。若恢复后按每秒 500 QPS 回源预热,覆盖 10000 个热点 key 约需 20 秒,应在这段时间继续允许短期 fallback。
指标包括 fallback 命中率、各类型占比、最老数据年龄、越过陈旧度的拒绝数和恢复清理耗时。长期非零的降级率往往意味着依赖或开关没有真正恢复。
七、常见误区与追问
- 误区:默认空数组永远安全。 空数组可能被解释为“确实没有”,影响推荐、风控或报表决策。
- 误区:缓存没过 TTL 就一定可用。 技术 TTL 可能大于业务允许的陈旧时间。
- 误区:降级结果也写入正常缓存。 会污染恢复后的结果并延长故障影响。
- 误区:HTTP 200 就应计为成功。 降级必须作为独立质量指标统计。
- 追问:价格可以用旧值吗? 只有业务明确承担价差且有时间界限时可以,否则应不可用。
- 追问:如何防跨租户泄漏? fallback key 和生成过程都包含租户、权限与地域上下文。
- 追问:依赖恢复后如何退出? 小流量回源验证、预热正常缓存,再失效 fallback 并逐步撤销开关。
八、加强记忆
设计降级数据要沿着“真、旧、权、标、清”检查:不伪造关键事实,旧数据受业务陈旧度限制,权限上下文绝不丢失,响应和指标显式标出降级,恢复后清理隔离缓存。能返回什么由业务语义决定,而不是由代码里哪个默认值最方便决定。