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",雪崩是"一大片同时失效或缓存挂了"
  • 击穿首选互斥锁(简单可靠),热点数据可用逻辑过期(不卡用户)。
  • 顺手把空值缓存或布隆过滤器补上,挡住穿透。

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

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

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

相关推荐
这个DBA有点耶1 天前
MVCC深入:Read View、版本链与快照读——InnoDB并发控制的内核
数据库·mysql·架构
DBA_G1 天前
从地面到云霄:GBase数据库在民航三大场景的落地实践
数据库
自由能燃气设备1 天前
商用全预混低氮冷凝锅炉免费方案vs付费方案对比+选型避坑指南
大数据·数据库·人工智能
科创致远1 天前
科创致远 ESOP 系统核心效能与实战价值展示
大数据·数据库·人工智能·精益工程
IT大白鼠1 天前
Redis 系列 · 第 01 篇——认知入门:Redis 是什么
redis·nosql
彧azz1 天前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
2601_962218611 天前
万象生鲜系统称重自动多退少补算法解决生鲜非标品痛点
大数据·数据库·人工智能·python·算法
全栈弄潮儿²⁰²⁴1 天前
AI Agent 开发实战(30):限流、缓存与成本控制
人工智能·gpt·缓存·agent·限流·agi·成本控制
张洛闻Eren1 天前
k8s云原生【第十课】:水平 Pod 自动扩缩容
运维·数据库·云原生·kubernetes·github
于平安1 天前
MySQL-触发器
数据库·mysql