缓存失效这件事,比想象中难

举报
柠檬-夏日清爽 发表于 2026/10/05 15:31:22 2026/10/05
【摘要】 讲清缓存的核心取舍,说明失效比写入难,梳理穿透和雪崩的成因,并给出四个不该用缓存的场景。

image.png

一、三个必须搞清的概念

一、缓存命中不了,性能反而更差。 加了缓存之后每次请求要多查一次缓存、还要做序列化反序列化。缓存命中率低的时候,这部分开销是纯亏。

二、失效比写入难。 写一次数据很难出错,因为有返回值、有报错。删掉缓存的逻辑往往藏在某个角落,永远不会被执行到——但正是它导致用户看到旧数据。

三、缓存过期时间和业务允许的不一致时间无关。 设 1 小时过期,意思是性能上 1 小时更新一次;业务上如果要求 5 分钟内看到更新,这个方案就是错的。这是产品决定,不是技术决定。

二、常见的几种缓存策略

一、Cache-Control。 告诉浏览器和中间缓存该怎么处理这个响应:

Cache-Control: max-age=3600     # 一小时内不用再问服务器
Cache-Control: no-cache          # 每次都要问,但服务器可以返回 304
Cache-Control: no-store          # 完全不缓存,敏感数据用

no-cache 和 no-store 的区别常被搞混。 no-cache 是"可以存但每次要验证",no-store 是"连存都不要存"。存密码页面的响应要用 no-store。

二、ETag。 服务器给每个资源算一个标识,客户端下次带上这个标识问服务器"没变吧",没变就返回 304,响应体是空的。适合内容会变但大部分时候不变的情况,比如文章页。

三、强制刷新。 Ctrl+F5 忽略缓存重新拉,这个在联调时经常救命。

三、缓存失效的几个坑

一、更新了数据但忘了删缓存。 这是最常见的。

// 只写了更新,忘了删
async function updateOrder(id, data) {
  await db.order.update(id, data);
}

结果就是:数据库里是新的,页面上是旧的,而且刷新多少次都没用(因为缓存还在)。

解法是把删缓存固定成更新函数的一部分,不给忘的机会:

async function updateOrder(id, data) {
  await db.order.update(id, data);
  await cache.del(`order:${id}`);   // 跟更新绑死
}

二、删了列表缓存没删详情缓存。 改完一个商品的名称,列表页是新的,点进详情还是旧名字。因为两个缓存都要清,而只清了一个。

三、先删缓存再更新数据库。 顺序反了会有并发问题:删完缓存、数据库还没改,这时另一个请求读到了旧值又写回了缓存。永远先改数据库,再删缓存。

四、缓存穿透。 查一个不存在的 key,缓存里没有,去数据库查也没有,于是每次都打数据库。恶意刷的话数据库会挂。

解法是把"查不到"也缓存起来,存一个空值标记,值设短一点:

const val = await cache.get(key);
if (val !== null) return val === 'NULL' ? null : JSON.parse(val);
const db = await query(key);
await cache.set(key, db ? JSON.stringify(db) : 'NULL', db ? 300 : 60);
return db;

五、缓存雪崩。 大量 key 同一时刻过期,同时打向数据库。解法是把过期时间加随机:

const ttl = 300 + Math.floor(Math.random() * 60);

四、什么时候不该用缓存

一、几乎不变的配置。 地区列表、枚举值这类东西,本来就不怎么变,放内存里就够,不需要分布式缓存。

二、写多读少的数据。 缓存是为读设计的,写得比读还多的数据用缓存只会增加无效开销。

三、要求实时准确的地方。 余额、库存这类数据,缓存带来的不一致不可接受,宁可慢一点。

四、刚开始的项目。 早期数据量小、请求量小,缓存带来的复杂度完全覆盖不了收益。等真的慢了再加,代码结构不需要提前为缓存改造太多。

五、一句总结

缓存不是"让系统变快的东西",是"用数据可能不准,换性能"的交易。

所以做决定的时候,要能回答三个问题:允许多长时间的不准?命中率预计多少?失效逻辑在哪个函数里? 三个都答得上来,再动手。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。