Redis 缓存实战:穿透、击穿、雪崩到底差在哪,以及一套能落地的预热方案

简介: 把穿透、击穿、雪崩三个高频混用的概念一次讲清:触发条件、破坏路径、处置手段逐项区分,配空值缓存、布隆过滤器、互斥锁、逻辑过期、TTL 打散等可直接照抄的代码与配置,并给出定位热点、分层预热、灰度放量、监控回看的落地流程和架构选型、容量计费要点。读完能带走一套可复用的缓存保护清单。

缓存扛住了 99% 的读,剩下 1% 的请求如果打穿到数据库,照样能把后端拖垮。穿透、击穿、雪崩这三个词经常被混着用,其实它们触发条件、破坏路径、处置手段完全不同。这篇把它们逐个拆开,再给一套可直接照着做的预热与保护方案。

一、先把三个概念分清,别再用错词

很多人把这三个词当成同义词在乱用,结果排查时方向就偏了。用一张表先把边界划清:

概念 触发条件 数据在不在库 请求特征 对后端的影响
缓存穿透 查询一个根本不存在的数据 不在 单个不存在的 Key 被高频查 缓存永远不命中,每次都落到数据库
缓存击穿 某个热点 Key 突然过期 在 同一个热点 Key 并发涌入 瞬时大量请求同时查同一行数据
缓存雪崩 大批 Key 同一时刻集中过期,或缓存实例整体不可用 在 全量或大范围 Key 同时失效 数据库瞬时承受数倍甚至数十倍流量

一句话记忆:

  • 穿透是查不存在的东西——攻击者或脏参数导致,缓存层形同虚设;
  • 击穿是一个热点 Key 过期——量不大但极集中,冲击的是"一行数据";
  • 雪崩是过期时间撞车或整层挂掉——冲击面是"整个数据库"。

危害等级依次递进:穿透是慢性消耗,击穿是瞬时冲高,雪崩是系统性故障。

二、穿透:让缓存"守住"不存在的 Key

穿透的根因很明确——缓存对不存在的 Key 不缓存,于是每次请求都直接打库。典型场景是恶意刷不存在的商品 ID、用户 ID(比如 user:-1、随机字符串参数),或者业务上确实存在大量"查无此人"的合法请求。

处置手段一:缓存空对象

查库为空时,也往缓存里写一个特殊值(如 __NULL__),并设一个较短的过期时间(例如 60~300 秒)。

String value = redis.get(key);
if (value == null) {
   
    // 缓存未命中,回源查库
    value = db.query(key);
    if (value == null) {
   
        // 空结果也写缓存,TTL 设短,防止脏数据长期占用
        redis.setex(key, 120, "__NULL__");
        return null;
    }
    redis.setex(key, 3600, value);
    return value;
}
if ("__NULL__".equals(value)) {
   
    return null; // 命中空值标记,直接返回,不查库
}

要点:空值 TTL 一定要短。否则一旦数据库里后来真的插入了这条数据,缓存里还挂着空标记,会出现"数据明明写进去了却读不到"的假故障。

处置手段二:布隆过滤器前置拦截

把库中所有合法 Key 的指纹灌进布隆过滤器,请求先过一层过滤器,明显不存在的 Key 直接返回。优点是内存占用小、判断快;缺点是存在误判率(说"可能存在"时未必存在,但说"不存在"时一定不存在),且删除数据不方便。

处置手段三:参数校验兜底

最容易被忽略、也最划算的一层:在入口把明显非法的 ID 拦掉。id <= 0、超长字符串、非预期字符集的参数,在业务层直接拒绝,根本不用走到缓存。

三、击穿:给热点 Key 加一把互斥锁

击穿发生在单个热点 Key 过期的那一瞬间。比如首页 Banner、大促主推商品,平时 QPS 上万,一旦缓存过期,这一瞬间所有并发请求发现缓存没了,会同时去查同一行数据并回写——数据库瞬时压力可能是正常值的几十倍。

处置手段一:互斥锁 / 单飞(singleflight)

只允许一个请求回源,其余请求短暂等待后重新读缓存。

public String getWithMutex(String key) {
   
    String value = redis.get(key);
    if (value != null) return value;

    String lockKey = "lock:" + key;
    // SET NX 抢占回源资格,避免大量请求同时打库
    if (redis.set(lockKey, "1", "NX", "EX", 10)) {
   
        try {
   
            value = redis.get(key);          // 双重检查:可能已被别的线程写入
            if (value != null) return value;
            value = db.query(key);
            if (value != null) {
   
                redis.setex(key, 3600, value);
            }
            return value;
        } finally {
   
            redis.del(lockKey);
        }
    } else {
   
        // 没抢到锁,短暂 sleep 后重试读缓存
        try {
    Thread.sleep(50); } catch (InterruptedException ignored) {
   }
        return redis.get(key);
    }
}

处置手段二:逻辑过期(永不过期)

不设物理 TTL,而是在 value 里附带一个"逻辑过期时间"。读到数据时先判断逻辑时间是否到期,到期则异步触发一个线程去刷新,当前请求仍返回旧数据。这样任何时候都有值可读,不会出现"缓存真空期"。

处置手段三:热点 Key 提前续期

对可预知的热点(大促商品、活动页),用定时任务在 TTL 到期前主动刷新,把"过期"这件事从被动事件变成主动行为。

四、雪崩:从"过期时间"和"缓存层可用性"两头防

雪崩有两条独立成因,要分开治理。

成因一:大批 Key 同时过期

常见于系统刚上线时批量灌数据、或定时任务统一刷新缓存。全部 Key 的 TTL 都设为 1 小时,那么 1 小时后它们会一起失效。

处置:TTL 打散。 在基础过期时间上加一个随机扰动:

// 基础 1 小时,随机浮动 ±10 分钟,避免集中过期
int ttl = 3600 + ThreadLocalRandom.current().nextInt(0, 600) - 300;
redis.setex(key, Math.max(ttl, 60), value);

成因二:缓存实例整体不可用

实例宕机、网络抖动、主备切换期间,所有请求会瞬时涌向数据库。

处置:

  1. 高可用架构。云数据库 Tair(兼容 Redis)的标准架构本身是主备双节点并带自动主备切换,能在主节点异常时自动提升备节点;集群架构则每个分片都是主备多节点。架构层面的容灾是雪崩防护的地基,单节点架构官方明确不建议用于生产。
  2. 熔断与降级。给数据库访问加并发上限或信号量,超出后走降级逻辑(返回兜底数据或排队),宁可部分用户等一等,也不让数据库被打死。
  3. 本地缓存作二级缓冲。在应用进程内用 Caffeine/Guava 做一层短 TTL 的本地缓存,Redis 不可用时仍能挡住一部分读请求。
  4. 提前预热。系统重启、大促开始前,把热点数据主动加载进缓存,避免开放瞬间的冷启动冲击。

五、一套可落地的预热流程

预热不是"把数据全塞进 Redis"这么粗暴,按下面的顺序做更稳:

第一步:定位热点。 不要凭感觉猜。云数据库 Tair/Redis 控制台在 CloudDBA 下提供 Top Key 统计(实时显示每个分片各数据类型的前三大 Key 与热 Key,支持查看近 4 天历史),以及离线全量 Key 分析(基于 RDB 备份,给出 Key 的内存占用分布与过期时间)。这两个工具能把热点从"猜"变成"测"。

第二步:分层预热。 优先序:首页/活动页 > 购物车主推商品 > 用户高频画像,按预估 QPS 排序,先灌最热的。灌数据时统一走上面提到的 TTL 打散。

第三步:灰度放量。 预热完成后不要立刻全量放流量,先放小比例观察数据库的 QPS 回落情况,确认缓存命中率正常再逐步放大。

第四步:建监控回看。 配置 CPU 使用率、内存使用率、连接数、带宽的告警阈值。官方文档给出的参考值包括:内存使用率超过 70%、一小时内增长率超过 20% 触发告警。出现告警时按"定位热点 → 优化热 Key"的顺序处理,在影响业务之前解决。

六、选型与成本:缓存容量不是越大越好

云数据库 Tair(兼容 Redis)按开通的实例容量收费,而不是按实际存储的数据量收费。开一个 2 GB 实例、里面只放了 256 MB 数据,仍按 2 GB 计价。这意味着盲目开大规格会直接浪费预算。

  • 架构选择:数据量少、压力可控、用作持久化存储 → 标准架构;数据量大、QPS 高、吞吐密集 → 集群架构;读多写少且读请求超过主节点上限 → 在标准或集群架构上开启智能读写分离,按需增加只读节点,且无需修改代码。
  • 容量与性能参考:Redis 开源版标准架构内存上限约 64 GB、约 10 万 QPS;集群架构内存上限约 16,384 GB(64 GB × 256 分片),整体性能随分片数线性增长。
  • 计费方式:按量付费灵活、适合突发或波动业务;包年包月单价更低、适合长期稳定业务;按量付费搭配资源包可进一步降低成本。变配不停机,业务增长时可随时调整。

具体价格与当前活动以官方页面实时展示为准,下单前建议先在控制台按预估容量和计费方式试算一次。

七、避坑清单(照着检查一遍)

  • [ ] 查不到的数据也写缓存,但空值 TTL 必须短(建议 ≤ 300 秒)
  • [ ] 热点 Key 回源必须加互斥锁,并在锁内做二次检查,避免重复回源
  • [ ] 所有缓存 TTL 加随机扰动,禁止整批数据用同一个固定 TTL
  • [ ] 生产环境不用单节点架构,选主备或集群,保证自动切换能力
  • [ ] 数据库访问必须有并发上限或降级,不给雪崩留直通通道
  • [ ] 大促/重启前主动预热,不要指望流量把缓存"自然填满"
  • [ ] 定期用 Top Key 统计检查大 Key 与热 Key,别等报警才查
  • [ ] 删除大 Key 优先用 UNLINK(异步释放),避免阻塞主线程;集群下用 HSCAN + HDEL 分批清理
  • [ ] 容量按实际需求开通,按容量计价,不是开越大越好

把穿透、击穿、雪崩分开治理,再配上一套"定位热点 → 分层预热 → 灰度放量 → 监控回看"的流程,缓存这层才算真正稳住。缓存的价值不在于"有",而在于"每一次都命中且后端不被击穿"。如果你的业务正准备从自建 Redis 迁到托管实例,可以直接从云数据库 Tair(兼容 Redis)开始,先按小规格试跑、观察监控指标,再逐步调整架构和容量。

相关文章
|
4月前
|
人工智能
Qwen3.8抢先体验!正式版即将发布并开源!
千问Qwen3.8即将开源,参数达2.4T,进化速度以“天”计,实力媲美Fable 5。预览版Qwen3.8-Max已上线阿里Token Plan等平台,限时优惠:日间Credits低至1折,夜间更优,个人/团队版月付仅35元起!
6285 218
|
安全 Docker 容器
漏洞扫描–-Awvs&Nessus(Docker版)
漏洞扫描–-Awvs&Nessus(Docker版)
漏洞扫描–-Awvs&Nessus(Docker版)
|
2天前
|
存储 人工智能 监控
2026年阿里云双十一大促活动有没有优惠券?优惠券种类、金额、领取与使用规则分享
2026年阿里云双11大促以优惠券为主要让利载体,按身份分层发放六大类券种。个人券六档,满200减10至满3000减150;企业券同门槛抵扣更高,最高满10000减800,企业认证用户宜优先以企业身份领取;学生专享券300元/年、每日限量;OPC专项券提供百万补贴;新客券个人满20减10、企业85折最高减1000元;续费券95折最高减100元,满2000元最划算。各类券互不叠加,以结算页为准。
|
10天前
|
存储 大数据 测试技术
Elasticsearch压测之Esrally压测报告解读
Elasticsearch压测之Esrally压测报告解读
110 6
|
15天前
|
存储 NoSQL 关系型数据库
表格存储 Tablestore:海量结构化数据随手存,我拿一张 10 亿行的表试了试
本文实测将日增8000万行、总量10亿行的埋点表从MySQL迁至阿里云Tablestore,详解宽表建模、主键设计、多元索引优化及冷热分层实践,分享迁移中空值存储、并发限流、生命周期配置三大避坑经验,验证其在海量点查与多维检索场景下的毫秒级性能。(239字)
|
17天前
|
缓存 弹性计算 网络协议
全球加速 GA 避坑指南:海外用户打开慢,八成不是服务器不行
海外用户打开慢,多半不是服务器配置不够,而是跨境网络在绕路。本文按踩坑顺序讲清全球加速 GA 的五个常见误区:把它当 CDN 买、跨境方向没定、标准型与基础型选错、加速 IP 类型改不了、计费账算不清,并给出配置顺序、三条验收标准和什么情况下不该买 GA。
152 3
|
24天前
|
Rust 网络协议 定位技术
rpi 这些扩展到底怎么选?一张工具地图看懂 16 个 Rust 插件
rpi 提供16个原生 Rust 插件,覆盖任务规划、代码分析、网络访问、运行观测、消息集成与语音交互等核心场景。本文以“选型地图”形式分类呈现,助你按需安装,避免盲目全量引入。(239字)
75 2
|
23天前
|
弹性计算 Linux Docker
2026年10月Docker镜像源清单:ECS旧入口与公共候选
本文梳理2023年10月主流容器镜像加速入口现状:阿里云、百度旧加速器已停更或终止服务;腾讯、华为云内网地址限特定环境;毫秒镜像(docker.1ms.run)与DaoCloud为可用公共候选。强调需按“环境适配→显式拉取→摘要校验”三步验证,不可盲目替换配置。(239字)
2026年10月Docker镜像源清单:ECS旧入口与公共候选
|
2月前
|
存储 SQL 缓存
MySQL索引为什么必须用B+树?从磁盘IO深度推导
本文深入剖析InnoDB选用B+树作索引的底层逻辑,从磁盘与内存万倍性能差异出发,系统对比二叉树、AVL、红黑树、B树、Hash、LSM等结构,阐明B+树“宽矮多叉、叶节点有序链表、目录数据分离”四大优势如何精准适配MySQL OLTP场景,贯通硬件约束、存储引擎实现与SQL调优实践。(239字)
277 2