← 返回题目列表

缓存冷启动时如何保护数据库?

中等 第 23 / 26 题 更新于 2026/09/30
缓存冷启动预热回源保护限流
学习 AI 实战项目

简化版

缓存冷启动时命中率低,若全量流量直接回源,数据库会瞬间承受数十倍压力。应先预热高价值热点,再通过回源限流、singleflight、分批放量、随机 TTL 和旧集群/快照兜底控制加载速度;数据库容量而不是入口流量决定可放开的 miss 数。

详细版

冷启动包括新集群上线、节点扩容、全量清缓存、机房切换和大版本 Key 变更。保护流程是:发布前从访问日志/业务清单选 Top Key;用受控并发加载并校验;新集群先承接少量流量;在线 miss 经过同 Key 请求合并和全局回源配额;命中率、数据库 QPS、P99 达标后逐步扩大。

不能追求预热全部数据。应按访问频率、加载成本和业务关键性排序,防止预热本身成为全表扫描或缓存写入洪峰。多实例本地缓存要错峰,TTL 加随机抖动,避免预热数据同一时刻失效。

若有旧集群,可双读或用旧集群作为迁移期后备,但要明确数据新鲜度与一致性;没有旧集群时可从快照恢复或返回有限 stale 数据。失败时应暂停放量而非无限重试,恢复完成后对漏预热和热点变化做复盘。

完整版教学

一、冷启动为什么比普通 miss 更危险

普通运行时只有少量 Key miss,数据库容量通常能覆盖;冷启动则大量 Key 同时不存在,miss 具有相关性。缓存命中率从 99% 降到 50% 时,原本 10 万 QPS 中数据库只接 1000 QPS,会变成约 5 万 QPS,增长 50 倍。

数据库一旦变慢,回源请求占满连接池,调用方超时重试,系统会进入“缓存未命中—数据库变慢—更多超时重试”的正反馈。冷启动保护的核心是限制回源速度,让缓存热度增长不超过权威存储承载能力。

记忆钩子:冷启动不是缓存容量问题,而是把数据库安全余量转换成可控的缓存填充速率。

二、先选真正值得预热的数据

访问通常服从长尾分布,少量热点贡献大部分请求。预热 Top 1% Key 可能恢复 70% 以上命中率,而全量预热会扫描大量永远不会访问的数据,浪费数据库和网络资源。选择标准包括近期频率、业务关键性、加载成本和即将发生的活动。

数据来源优点风险
最近访问日志 Top Key接近真实热点昨日热点可能已变化
活动/运营清单可提前覆盖确定热点依赖业务维护准确性
旧集群 keyspace覆盖当前热数据可能携带过期/废弃 Key
数据库全表完整成本极高,常无必要
缓存快照恢复快需校验版本和过期语义

预热清单应有上限和版本,不能让任意业务提交百万 Key 无节制加载。

三、用数据库余量计算加载速率

假设数据库在目标 SLO 下容量 12000 QPS,在线正常业务即使无缓存也有 2000 QPS 的必须请求,为故障保留 3000 QPS,则可用于冷启动回源的预算只有 12000-2000-3000=7000 QPS。预热和在线 miss 要共享这 7000,而不是各自认为自己可用全部容量。

如果要加载 1400 万个 Key,平均每次一个数据库查询,以 7000 QPS 至少需要 2000 秒,约 33 分钟。想在 5 分钟完成,必须用批量加载、快照或增加数据库读取副本,而不能简单把并发调大。

safe_fill_rate = db_safe_capacity - mandatory_db_traffic - failure_headroom
warmup_time >= key_count / effective_batch_fill_rate

四、离线预热与在线填充怎样配合

离线预热先覆盖可预测热点,在线填充处理实际访问偏差。预热任务使用批量查询与 pipeline 写缓存,但要分别限制数据库读和缓存写 QPS。每批写后抽样校验值、TTL 和序列化版本。

在线 miss 通过 singleflight 合并同 Key 请求,避免热点同时回源;全局信号量限制不同 Key 的回源并发。等待者服从自己的 deadline,超限时返回降级或旧值,不能把所有请求堆在内存队列。

预热:Top Key -> 批量查 DB -> 校验 -> pipeline 写新缓存
在线:miss -> same-key 合并 -> 获取回源配额 -> DB -> 写缓存
                 无配额 -> stale/降级/快速失败

五、灰度切流和命中率门槛

新集群不应直接承接 100% 流量。可以按实例、租户或用户哈希从 1%、5%、20%、50% 逐步放量,每一步观察命中率、缓存 P99、数据库 QPS/连接、错误率和 Key 分布。任一指标超阈值立即停止扩大。

仅看总体命中率可能误导:大量廉价 Key 命中掩盖少量昂贵查询 miss。应增加“节省数据库成本”的加权命中率,或按业务/查询成本分组。P0 业务也应单独看命中。

若旧集群仍可用,可在新集群 miss 后先读旧集群再决定回源,形成平滑迁移。但旧值要满足新版本序列化和新鲜度要求。

六、TTL 与热度变化如何处理

所有预热 Key 使用同一 TTL,会在 TTL 到期时再次集体 miss。应在基础 TTL 上加抖动,例如 30 分钟 ± 5 分钟;超热点可以采用逻辑过期,由后台提前刷新。抖动范围要足以摊平回源,而不是只加几秒装饰。

热点会随新闻、活动和时间变化。预热后仍需实时检测 QPS Top Key,并允许追加清单。若新热点出现,singleflight 与回源限额负责保护数据库,后台再主动加载。

缓存 Key 版本升级时,新旧 Key 可双读:先读 v2,miss 后读 v1 并转换回填 v2;稳定后停止 v1。这比一次全量删除旧缓存更安全。

七、故障与恢复演练

需要模拟新集群空数据、预热任务中断、数据库变慢、缓存部分分片失败和放量回滚。预热任务必须可断点续跑且幂等,不能重启后从头扫描;切流配置要有自动停止条件。

指标包括预热进度、加载 QPS、成功/失败 Key 数、在线 miss 合并率、回源拒绝、命中率分组、数据库余量和预计完成时间。恢复后检查是否因预热写入造成内存淘汰或副本滞后。

warmup_total_keys: 14000000
warmup_completed: 8200000
fill_qps: 6800
online_miss_coalesced: 76%
db_headroom: 28%
traffic_to_new_cache: 20%

八、常见误区与追问

  • 误区:冷启动就应该预热全量数据。 长尾数据可能永远不访问,全量扫描会浪费数据库和缓存容量。
  • 误区:命中率达到 90% 就可全量切流。 要看昂贵查询和核心业务命中率,以及数据库实际余量。
  • 误区:增加预热线程能线性缩短时间。 数据库、网络和缓存写入都有安全上限,过并发会使整个系统变慢。
  • 误区:预热结束后风险就消失了。 相同 TTL 会制造下一轮同时过期,热点也会动态变化。
  • 追问:singleflight 是否足够? 它通常只合并单进程同 Key 请求,还需全局回源限流和多实例协调。
  • 追问:如何选择灰度单位? 选择能稳定路由且便于回滚的租户、用户哈希或实例组,避免同一会话来回切换。
  • 追问:旧集群可以直接作为后备吗? 可以,但需校验数据格式、版本与最大陈旧时间,并设置退出期限。

九、加强记忆

按“挑热点、算余量、限速填、合并 miss、分批切、错峰过期”保护冷启动。预热不是越多越好,数据库安全余量决定加载速率;离线预热负责已知热点,在线 singleflight 与全局配额负责未知热点;最后通过灰度切流和 TTL 抖动避免首次与下一次回源洪峰。