因为专注所以专业
助力成长与创新,汇集前沿程序开发观点

缓存过期时间都设成一样的,凌晨数据库突然被打满,是不是 key 同时失效闹的?

2026年9月15日 阅读:96

缓存 key 都设成同一个过期时间,到点一起失效,本该被缓存挡住的请求会在短时间内同时回到数据库,这就是大家常说的缓存雪崩。按 2026 年的交付习惯,处理顺序是先确认是不是时间对齐型故障,再分三层下手:TTL 打散、回源保护、热点数据单独处理。只做 TTL 打散这一层,遇到发版批量重建缓存或单个热点 key 失效,数据库一样可能被打满。

为什么过期时间设成一样,凌晨数据库就会被拉满

单个 key 过期只影响一条查询;一批 key 在同一秒过期,等于把原本由缓存拦下的请求一次性还给数据库。命中率从常见的九成以上掉到接近零,数据库连接池和磁盘 IO 往往先被占满,紧接着接口超时、上游重试,压力再被放大一轮。

值得单独说的是,自然到期常常不是主因。发版时批量清缓存、预热脚本一次性把 key 全写一遍,更容易让过期时间撞在一起,因为这类操作的时间点是人手动对齐的。所以凌晨的尖峰未必是 TTL 设错,也可能是前一天晚上的发布留下的后遗症。先看三个信号:

  • 命中率表现:断崖式下落,几分钟到十几分钟后自行恢复;
  • 时间特征:集中在整点、凌晨低峰,或发版后 1~10 分钟;
  • 连带现象:数据库连接数占满、慢查询集中在少数几条 SQL、接口超时率同步上升。

有一句可以单独摘录:缓存雪崩的根因不是缓存挂了,而是大量 key 在同一时刻失去保护,回源流量没有缓冲。

先分清是同时失效,还是缓存穿透、数据本身变了

在把问题归到过期时间之前,先看时间是否集中、key 的剩余 TTL 是否扎堆、数据库 QPS 与缓存 QPS 的比例是否同步变化。若命中率几分钟内快速回升,多半是集中失效;若长期低命中,优先怀疑穿透或者缓存粒度不对。

  1. 看时间相关性:把接口超时、数据库 QPS 和发版记录放在同一条时间轴上,确认尖峰是否落在发版后或整点;
  2. 看 key 分布:抽样统计线上 key 的剩余 TTL,若大量 key 落在同一分钟内,基本可以确认;
  3. 看回源行为:数据库 QPS 是否接近缓存 QPS、慢查询是否高度重复;若数据库 QPS 没涨,问题多半在网络或应用侧。

这里可以先立一条边界:如果缓存命中率长期低于 50%,问题通常不在过期时间,而在缓存粒度和 key 设计,错开 TTL 的收益有限。

TTL 怎么错开:抖动加多少、在哪里加

TTL 打散的做法,是给基础过期时间叠加一个随机量。经验区间是:基础 TTL 按数据变更频率定,常见从 10 分钟到 24 小时;抖动比例常见取基础 TTL 的 5%~20%,也可以用固定 1~10 分钟随机。抖动要在写入缓存时生成并固定下来,不要每次读取都重新计算,否则同一个 key 的过期时间会漂移,排查起来更麻烦。

  1. 基础 TTL 分档:更新快的数据用短 TTL,更新慢的用长 TTL,不要所有 key 一个值;
  2. 叠加随机抖动:让同批写入的 key 把过期时间分散到一段时间窗口里;
  3. 批量写入分批:预热或重建缓存时按批写入,批与批之间留出间隔,避免新写入的 key 又同时到期。

每层的作用并不相同:基础 TTL 决定数据新鲜度的上限,抖动只削峰不消除回源,分批写入是为了不让集中失效从自然到期搬到发版时刻。可引用一句:TTL 抖动只能把尖峰削平,真正的保护是让同一个 key 在同一时刻只有一个请求去查数据库。

两种常见做法可以放在一起对照,差别不在代码量,而在要接受什么样的旧值窗口:

  • 统一 TTL 加随机抖动:改动通常半天到一天,适合大多数读多写少场景;一致性延迟随 TTL 波动,热点 key 到期时仍会有一次回源;
  • 逻辑过期加异步刷新:改动常见一到三天,适合读取量大、更新又少的基础数据;需要额外的线程或定时任务,且要接受分钟级旧值。

选择口径按数据重要度来:能容忍几秒到几分钟旧值的,用前者通常够用;读取集中、更新又少的基础数据,后者更省数据库压力。两种都要业务侧先确认旧值窗口。

错开 TTL 之后,回源这道闸怎么收

错开过期时间解决的是时间对齐,回源保护解决的是并发对齐。常见做法是单飞或互斥重建:同一个 key 失效时只允许一个请求去查数据库并回写缓存,其余请求短暂等待或先返回旧值。

  • 锁的粒度:按 key 加锁,不用全局锁,否则会把不同数据的请求串成一条线;
  • 等待窗口:按接口超时预算给,常见几百毫秒到 2 秒,超时就走降级;
  • 限流余量:回源限流阈值按数据库承载能力留出 20%~30% 余量,防止缓存层正常、数据库却顶不住;
  • 降级兜底:返回旧值还是默认值,要提前和业务确认,不宜由开发单方面决定。

交付现场常见一种约束:只有一个数据库实例,缓存中间件还和其他业务共用,发版窗口只有半小时,业务方要求上线时整批重建缓存。我们的做法是先把 TTL 抖动和分批预热写进发布脚本,再给回源加单飞和限流,并把峰值观测加进发布后的盯盘清单。代价是发布多花 10~20 分钟,换来的是上线后数据库连接不被瞬间打满,少一次回滚重发。验收看三个数:命中率是否稳得住、数据库 QPS 峰值是否回到可承受区间、故障恢复时间是否缩短;经验区间是峰值不再形成尖刺、连接池占用控制在七成以内。

哪些场景适合这么做,哪些不必折腾

适合做 TTL 错开和回源保护的场景:读多写少、缓存命中率直接影响数据库负载、业务能容忍短时间旧值。按 2026 年的交付习惯,这三条里缺一条,收益都会打折扣。

不适合或不必上的情况也要说清楚:强一致要求的场景不适合用旧值兜底;数据量小、数据库本身余量充足时,加随机抖动和单飞的维护成本可能高于收益;key 数量本来就少、过期时间天然分散时,额外处理的意义不大。

边界可以独立摘录:如果缓存命中率长期偏低,先修缓存粒度和 key 设计;错开过期时间只对时间对齐型故障有效。

常见问题

缓存过期时间设多长比较合适?

按数据更新频率分档,常见区间从 10 分钟到 24 小时;更新频繁的用短 TTL,基础数据用长 TTL,不建议所有 key 一个值。

随机抖动加多少秒才有效?

经验区间是基础 TTL 的 5%~20%,或固定 1~10 分钟随机;关键是写入缓存时一次算好,不要每次读取都重算。

缓存预热可以一次全写完吗?

不建议。分批写入并留出间隔,否则新写入的 key 会在同一时间点集中到期,等于人为制造一次尖峰。

逻辑过期是不是会一直返回旧数据?

会有旧值窗口,长短取决于异步刷新的速度;适合能容忍分钟级旧值的热点数据,强一致场景不要用。

用了缓存集群是不是就不会集中失效?

集群解决的是容量和可用性,不解决过期时间对齐;所有 key 同一秒到期,回源流量一样会同时压向数据库。


如果正遇到凌晨或发版后数据库被打满,先查 key 的 TTL 分布和命中率曲线,再决定是改 TTL 还是加回源保护。TTL 错开适合时间对齐型故障;命中率长期偏低、或业务不能容忍旧值的场景,应优先修缓存结构或直接走数据库,不必强上这套方案。

有类似的项目需求?
联系我们,获取一对一项目参考方案
获取方案
准备好开始了吗,
那就与我们取得联系吧!
13370032918
了解更多服务,随时联系我们
请填写您的需求
您希望我们为您提供什么服务呢
您的预算

微信二维码
扫码添加客服微信
专业对接各类技术问题
联系电话
13370032918 (金经理)
电话若占线或未接到、就加下微信
联系邮箱
349077570@qq.com
提交成功
感谢您的信任,我们会尽快与您联系!
为您推荐以下案例