缓存雪崩导致接口大量超时怎么办? 极客雨诺 提问于 2026-03-13 02:09:21 阅读 10 优化 我们线上有个商品详情页,用了 Redis 缓存,结果昨天缓存集体过期,瞬间数据库被打爆,接口基本都超时了。之前设置了统一的过期时间,比如都是 3600 秒,现在想优化但不知道咋下手。 听说可以加随机过期时间?但我试了下感觉治标不治本。有没有更稳妥的做法?比如用互斥锁或者永不过期策略?具体该怎么写啊? 现在临时加了限流,但用户体验很差。求真实项目里怎么处理这种缓存雪崩问题? 缓存优化缓存雪崩 我来解答 赞 1 收藏 分享 生成中... 手机扫码查看 复制链接 生成海报 反馈 发表解答 您需要先 登录/注册 才能发表解答 1 条解答 シ明艳 Lv1 缓存雪崩这破事我之前也遇到过,说白了就是同一时间大量key过期,请求全打DB上去了。 给你几个实战中常用的方案: 方案一:永不过期 + 逻辑过期 把Redis的过期时间去掉,改成在value里存一个过期时间戳,读取时判断是否需要刷新: class CacheService { private $redis; // 缓存永不过期,靠逻辑判断 public function getProduct($productId) { $cacheKey = "product:{$productId}"; $data = $this->redis->get($cacheKey); if (!$data) { return $this->getProductFromDB($productId); } $cache = json_decode($data, true); // 逻辑过期:超过30分钟就重新计算 if (time() - $cache['timestamp'] > 1800) { // 丢给后台异步更新,不阻塞请求 go(function() use ($productId) { $this->refreshProductCache($productId); }); return $cache['data']; // 返回旧数据先扛着 } return $cache['data']; } public function refreshProductCache($productId) { $data = $this->getProductFromDB($productId); $this->redis->set("product:{$productId}", json_encode([ 'data' => $data, 'timestamp' => time() ])); } } 这个方案最稳,请求不会被阻塞,短暂返回旧数据也没事。 方案二:互斥锁重建 如果一定要最新数据,用锁来控制只有一个请求去DB查: public function getProduct($productId) { $cacheKey = "product:{$productId}"; $data = $this->redis->get($cacheKey); if ($data) { return json_decode($data, true); } // 加锁,只有抢到锁的请求去查DB $lockKey = "lock:product:{$productId}"; $lock = $this->redis->set($lockKey, 1, ['NX', 'EX' => 10]); // 10秒锁 if ($lock) { try { $data = $this->getProductFromDB($productId); $this->redis->setex($cacheKey, 3600, json_encode($data)); return $data; } finally { $this->redis->del($lockKey); } } else { // 没抢到锁,睡一下再重试读取 usleep(50000); // 50ms return $this->getProduct($productId); } } 方案三:随机过期时间 + 预热 随机过期时间确实治标,但配合预热就好多了: // 预热:系统启动时把热点数据先加载进去 public function warmupCache() { $productIds = $this->getHotProductIds(); // 热门商品ID foreach ($productIds as $id) { $data = $this->getProductFromDB($id); // 随机过期时间 3600 ~ 7200 秒,分散开 $ttl = 3600 + rand(0, 3600); $this->redis->setex("product:{$id}", $ttl, json_encode($data)); } } 建议用crontab定时任务每天凌晨流量低峰期跑一次预热。 我的经验是:优先用方案一(永不过期),这是目前最稳的方案,基本不会出问题。互斥锁适合对数据实时性要求高的场景,但会增加响应时间。 另外,别忘了给DB加个连接池和慢查询监控,别让DB本身成为瓶颈。 回复 点赞 2026-03-13 03:02 加载更多 相关推荐 1 回答 18 浏览 缓存穿透导致接口被恶意刷爆怎么办? 我们线上有个商品详情接口,最近被爬虫疯狂请求不存在的ID,直接打穿缓存压垮数据库了。试过加布隆过滤器但没生效,是不是哪里写错了? 这是我现在用的缓存逻辑: async function getProd... 司马春豪 优化 2026-02-24 14:24:22 1 回答 25 浏览 Node.js 后端接口响应慢,前端 Vue 页面加载卡顿怎么办? 我用 Node.js 写了个接口,返回用户列表数据,但每次请求都要 2-3 秒,导致 Vue 页面白屏很久。已经试过加缓存,但效果不明显,是不是哪里写得不对? 前端是用 Vue 3 + Axios 请... 国凤 前端 2026-03-04 08:19:22 2 回答 54 浏览 Vue请求缓存导致数据更新不及时怎么办? 最近在做Vue项目时遇到个奇怪的问题,我给接口设置了Cache-Control: max-age=300,但页面刷新时数据总比实际延迟很久。比如商品价格修改后,用户需要等很久才能看到新价格。 我试过手... 司空子格 优化 2026-02-18 10:39:39 2 回答 49 浏览 Memory Cache缓存导致动态组件样式残留怎么办? 在做页面切换时用了Memory Cache缓存组件状态,但发现上一个页面的CSS变量样式残留了,比如这个示例: :root { --primary-color: #4CAF50; } .dynamic... 程序猿东成 优化 2026-02-11 22:36:23 2 回答 22 浏览 微信支付回调超时后重复生成订单怎么处理? 在集成微信H5支付时遇到个难题,用户支付成功后回调接口偶尔会超时,导致订单重复创建。 我尝试在支付回调接口里用setTimeout模拟网络延迟,发现当延迟超过微信规定的10秒超时时间后,微信会重新发起... 天朝 移动 2026-02-11 09:21:35 1 回答 73 浏览 Vue移动端HTTPS页面请求http接口导致Mixed Content错误怎么办? 我在开发Vue移动端应用时遇到了HTTPS问题,当页面切换到HTTPS后,调用本地测试接口时控制台报Mixed Content错误。尝试过在nginx配置强制HTTPS,但真机测试还是加载失败。 代码... 子晨的笔记 移动 2026-02-04 17:23:31 2 回答 81 浏览 Redis缓存雪崩怎么解决?随机过期时间设置不管用? 最近在优化项目缓存时遇到个难题:我们用了Redis存热点数据,但发现大量key会在同一时间集中过期。昨天测试时,设置了统一30分钟过期时间的用户信息缓存突然全失效,导致数据库瞬间被打爆。 我试过给过期... Mc.振莉 优化 2026-01-29 10:42:33 2 回答 32 浏览 Redis缓存过期后怎么避免缓存击穿? 最近项目高并发接口出现缓存击穿问题,当Redis缓存过期后,大量请求直接打到数据库。我尝试用加锁方式让一个线程更新缓存,但发现锁竞争导致接口响应变慢,而且偶尔还是会有脏数据穿透,有没有更好的解决方案?... 名轩(打工版) 优化 2026-01-27 11:38:44 1 回答 7 浏览 Ajax 请求被缓存了怎么办? 我用 fetch 发起一个 GET 请求获取用户数据,但发现第二次请求直接返回了缓存结果,根本没发到服务器!明明后端数据已经变了。 试过在 URL 后面加时间戳参数,比如 ?t=Date.now(),... Mr.卫红 前端 2026-03-12 23:00:19 1 回答 2 浏览 LocalStorage缓存数据在Vue中怎么避免重复请求? 我用localStorage缓存了用户信息,但每次刷新页面还是会重新请求接口,明明缓存里已经有数据了,是不是哪里写错了? 我试过在created里判断localStorage有没有user,有就直接用... UP主~志燕 优化 2026-03-12 10:46:23
给你几个实战中常用的方案:
方案一:永不过期 + 逻辑过期
把Redis的过期时间去掉,改成在value里存一个过期时间戳,读取时判断是否需要刷新:
这个方案最稳,请求不会被阻塞,短暂返回旧数据也没事。
方案二:互斥锁重建
如果一定要最新数据,用锁来控制只有一个请求去DB查:
方案三:随机过期时间 + 预热
随机过期时间确实治标,但配合预热就好多了:
建议用crontab定时任务每天凌晨流量低峰期跑一次预热。
我的经验是:优先用方案一(永不过期),这是目前最稳的方案,基本不会出问题。互斥锁适合对数据实时性要求高的场景,但会增加响应时间。
另外,别忘了给DB加个连接池和慢查询监控,别让DB本身成为瓶颈。