Redis缓存击穿:热点Key过期打崩数据库的3种解决方案

Redis 缓存击穿:热点 Key 过期打崩数据库的 3 种解决方案

缓存击穿、缓存穿透、缓存雪崩经常被混淆。本文用一个「首页热点配置」的真实故障,讲清楚三者的区别,重点给出缓存击穿的 3 种解决方案(互斥锁 / 逻辑过期 / 异步重建),并附可直接使用的代码。

一、问题案例

首页有一个「今日推荐」接口,查一个配置对象,QPS 数千。为了抗压,我给这个配置加了 Redis 缓存,过期时间 10 分钟。

上线第二天晚上,数据库连接数突然打满,首页接口大面积超时。监控显示:DB 的 QPS 从几百瞬间飙到几万,持续几秒又回落。

排查后发现,出问题的只有「今日推荐」这一个 key------它在过期的那一秒,几千个请求同时发现缓存没了,全部穿透到数据库。这不是雪崩,是击穿

二、原理详解:击穿、穿透、雪崩的区别

类型 触发点 范围 典型场景
击穿 单个热点 key 过期瞬间被并发穿透 单个 key 热门商品、首页配置
穿透 查询一个根本不存在的 key 单个 key 恶意请求、不存在的 id
雪崩 大量 key 同时过期,或 Redis 宕机 全局 过期时间没打散、缓存层故障

击穿的关键特征:热点 key + 过期瞬间 + 高并发。三者缺一不可。普通 key 过期被穿透,压力不大;热点 key 但没并发,也不会打崩。

三、实战代码:3 种解决方案

方案一:互斥锁(最常用)

缓存未命中时,只让一个请求去查库并重建缓存,其余请求等待:

java 复制代码
public String getConfig() {
    String v = redis.get("config:today");
    if (v != null) return v;

    // 只有一个请求能拿到锁去查库重建
    boolean locked = redis.setIfAbsent("config:today:lock", "1", 3, TimeUnit.SECONDS);
    if (locked) {
        try {
            v = db.query();
            redis.set("config:today", v, 10, TimeUnit.MINUTES);
        } finally {
            redis.delete("config:today:lock");
        }
    } else {
        // 拿不到锁,稍等后重查一次缓存
        Thread.sleep(50);
        v = redis.get("config:today");
    }
    return v;
}

适用:数据强一致、允许短暂等待。缺点:拿锁失败的请求要重试,代码稍繁琐。

方案二:逻辑过期(不物理删除 key)

key 永不物理删除,值里存一个「逻辑过期时间戳」。读到已逻辑过期的值,先返回旧值顶着,后台异步重建:

java 复制代码
class ConfigData {
    String value;
    long expireAt; // 逻辑过期时间戳
}

public String getConfig() {
    ConfigData data = redis.get("config:today");
    if (data == null) return rebuildWithLock();
    if (System.currentTimeMillis() < data.expireAt) return data.value;

    // 已逻辑过期:先返回旧值,异步重建
    asyncRebuild();
    return data.value;
}

适用:热点数据、对实时性不敏感。优点:用户永远不等待;缺点:会短暂返回旧值。

方案三:永不过期 + 后台定时刷新

热点 key 直接不设过期时间,用一个定时任务或消息队列,在数据变更时主动更新缓存。适合「数据量小、变更少、必须强一致」的配置类场景。

四、延伸:顺带防穿透

穿透(查不存在的 key)的防法:

  1. 空值缓存:把「不存在」也缓存起来(短过期时间),避免每次都打库。
  2. 布隆过滤器:在缓存前用布隆过滤器拦截不存在的 key。

五、总结

  • 击穿、穿透、雪崩是三种不同的问题,先分清再下手:击穿是"一个热点 key 过期",穿透是"查不存在的 key",雪崩是"一大片同时失效或缓存挂了"
  • 击穿首选互斥锁(简单可靠),热点数据可用逻辑过期(不卡用户)。
  • 顺手把空值缓存或布隆过滤器补上,挡住穿透。

我是无羡(小剑),全栈偏后端的独立开发者。

作品集:无羡 · 独立开发者作品集

如果对你有帮助,欢迎点赞、收藏、关注。

相关推荐
Carl_.Net软开19 分钟前
NSSM后台启动influx时序数据库
数据库·时序数据库
IPdodo_31 分钟前
静态 IP 访问异常排查:403/429 归因与迁移验收
服务器·网络·数据库·python·网络协议·php·性能测试
DevOpenClub32 分钟前
PDF 多格式解析如何避免混用输出:TEXT、HTML、XML 与 TAG 数据契约
xml·前端·数据库·pdf·html
meilindehuzi_a39 分钟前
从域名到数据库:React + Node.js 项目部署全流程与用户访问链路
数据库·react.js·node.js
xixiaoyunya1 小时前
Redis 缓存一致性方案深度对比:从理论到工程落地
redis·spring·缓存
泡干脆面就番茄1 小时前
MySQL_流程控制_分组查询与连接查询详解
数据库·mysql
Bode_20021 小时前
全生命周期 SQL 控制
数据库·智能制造
西西弗Sisyphus1 小时前
Qt 在无边框窗口上做一套换肤系统
开发语言·数据库·qt
神仙别闹2 小时前
基于 QT(C++)实现操作系统
数据库·c++·qt