1962 字
10 分钟
缓存穿透、击穿、雪崩的区别与解决方案
  1. 1Redis 系列导读:知识地图、必会主线与复习顺序
  2. 2Redis 中常见的数据类型有哪些?
  3. 3Redis 通常应用于哪些场景?
  4. 4Redis为什么这么快?
  5. 5Redis 常用的过期时间、删除 Key 命令有哪些?
  6. 6Redis 的过期 Key 是如何被删除的?
  7. 7Redis 内存满了怎么办?有哪些淘汰策略?
  8. 8缓存穿透、击穿、雪崩的区别与解决方案本文
  9. 9Redis 如何保证缓存与数据库的数据一致性?
  10. 10Redis 的持久化机制有哪些?
  11. 11Redis 主从复制的完整流程是什么?
  12. 12Redis 的哨兵机制是什么?
  13. 13Redis Cluster 模式与 Sentinel 模式的区别是什么?
  14. 14Redis 支持事务吗?如何实现?
  15. 15Redis 中如何实现分布式锁?
  16. 16Redis 的 Lua 脚本功能是什么?如何使用?
  17. 17如何解决 Redis 中的热点 Key 问题?
  18. 18Redis BigKey 有什么危害?如何发现和治理?
  19. 19为什么 Redis 设计为单线程?6.0 版本为何引入多线程?
  20. 20Redis 的 LRU 和 LFU 有什么区别?
  21. 21Redis 数据类型和底层编码有什么区别?
  22. 22Redis 中跳表的实现原理是什么?
  23. 23Redis 的 ZSet 为什么使用跳表,而不是平衡树?
  24. 24Redis 的 RDB 快照如何生成?为什么会有写时复制?
  25. 25Redis 的 AOF 刷盘和重写有什么区别?
  26. 26Redis 断线后如何通过 PSYNC 部分重同步?
  27. 27Redis 主从切换为什么会丢数据?WAIT 能解决吗?
  28. 28Redis 集群会出现脑裂问题吗?
  29. 29Redisson 看门狗(watch dog)机制了解吗?
  30. 30Redis Cluster:哈希槽、Gossip 与故障转移
  31. 31Redis Pipeline 为什么能提高吞吐?能保证原子性吗?
  32. 32Redis 的 SCAN 和 KEYS 有什么区别?
  33. 33Redis 变慢时如何排查?SLOWLOG 能看到所有耗时吗?
  34. 34Redis 和 MySQL 有什么区别?
  35. 35Redis 为什么使用 SDS,而不是 C 字符串?
  36. 36Redis 的哈希表如何处理冲突和渐进式 rehash?
  37. 37Redis Cluster 的 MOVED 和 ASK 重定向有什么区别?
  38. 38Redis Cluster 为什么会报 CROSSSLOT?Hash Tag 怎么用?
  39. 39Redis 如何实现限流?固定窗口和滑动窗口怎么选?
  40. 40Redis Stream 如何保证消息消费?ACK 和 PEL 是什么?
  41. 41Redis 删除数据后为什么内存不下降?如何理解内存碎片?

一、缓存穿透、击穿、雪崩的区别#

1. 缓存穿透#

定义: 查询的数据在 Redis 和数据库中都不存在,导致每次请求都绕过缓存访问数据库。

产生原因:

  • 查询不存在的数据。
  • 恶意请求大量不存在的 Key。

解决方案:

  1. 缓存空值
    • 查询数据库后,如果数据不存在,就将空值缓存到 Redis,并设置较短的过期时间。
    • 优点:实现简单,能够减少重复的无效查询。
    • 缺点:占用缓存空间;数据后来创建时,可能暂时读到空值。
  2. 布隆过滤器
    • 将可能存在的数据提前加入布隆过滤器。
    • 请求到来时,先判断数据是否可能存在。
    • 如果确定不存在,直接返回,不再查询 Redis 和数据库。
    • 优点:空间效率高,可以过滤大量无效请求。
    • 缺点:存在误判,标准实现不支持直接删除元素。

2. 缓存击穿#

定义: 某个热点 Key 突然失效,大量并发请求同时访问数据库,造成数据库压力骤增。

产生原因:

  • 热点数据过期。
  • 热点数据被删除或失效。

解决方案:

  1. 互斥锁
    • 只有一个线程获取锁并查询数据库、重建缓存。
    • 其他线程等待、重试或返回暂时不可用。
    • 优点:减少重复查询,重建逻辑清晰。
    • 缺点:其他请求可能等待,增加响应延迟。
  2. 逻辑过期
    • 缓存数据中保存业务过期时间,而不是直接依赖 Redis 的物理过期时间。
    • 数据逻辑过期后,仍保留在 Redis 中。
    • 请求可以先返回旧数据,同时由一个线程异步重建缓存。
    • 优点:请求延迟低,能够减少数据库瞬时压力。
    • 缺点:允许短暂读取旧数据,需要处理重建失败等问题。

3. 缓存雪崩#

定义: 大量缓存 Key 同时失效,或者 Redis 整体不可用,导致大量请求集中访问数据库。

产生原因:

  • 大量 Key 设置了相同的过期时间。
  • Redis 服务宕机或发生网络故障。

解决方案:

  1. 过期时间加随机值:避免大量 Key 同时过期。
  2. 热点数据不过期或使用逻辑过期:降低关键数据集中失效的风险。
  3. Redis 高可用:根据需求使用副本、Sentinel 或 Redis Cluster 等方案。
  4. 限流、熔断和降级:控制数据库承受的请求量,优先保障核心业务。
  5. 本地缓存:缓存部分热点数据,在 Redis 故障时提供有限的缓冲。

4. 三者对比#

对比项缓存穿透缓存击穿缓存雪崩
核心原因查询的数据不存在热点 Key 失效大量 Key 失效或缓存整体不可用
影响范围无效查询请求单个热点 Key大量业务请求
主要方案缓存空值、布隆过滤器互斥锁、逻辑过期随机过期时间、高可用、限流降级

记忆口诀:穿透是查不到,击穿是热点没了,雪崩是大量缓存一起失效。

二、布隆过滤器#

1. 原理#

布隆过滤器是一种空间效率较高的概率型数据结构,用于判断一个元素是否可能存在于集合中。

基本原理:

  1. 初始化一个所有位均为 0 的位数组。
  2. 添加元素时,使用多个哈希函数计算数组位置,并将对应的位设置为 1。
  3. 查询元素时,重新计算这些位置:
    • 只要有一个位置为 0,就能确定元素不存在。
    • 如果所有位置都是 1,只能说明元素可能存在。

2. 缺点#

  • 存在误判:可能把实际不存在的元素判断为存在。
  • 标准实现不支持直接删除:随意将某些位改回 0,可能影响其他元素的判断。
  • 无法直接获取原始数据:不能替代 Redis 或数据库。
  • 需要合理设置容量和误判率:容量超出预期时,误判率可能升高。

注意:标准布隆过滤器不会漏判已经正确添加且未被错误修改的元素。

三、互斥锁与逻辑过期#

1. 互斥锁#

核心思想:只允许一个线程重建缓存,其他线程等待或重试。

处理流程:

  1. 多个请求发现热点 Key 不存在。
  2. 所有请求尝试获取锁。
  3. 只有一个线程获取成功。
  4. 获得锁的线程查询数据库并重建缓存。
  5. 其他线程等待或重试,读取重建后的缓存。

分布式场景中,可以使用 Redis 的 SET key value NX EX seconds 获取带过期时间的锁,并在释放锁时校验持有者身份。

特点:

  • 优点:减少数据库重复查询,通常偏向数据新鲜度。
  • 缺点:请求可能等待,增加响应延迟。
  • 注意:需要考虑锁过期、异常释放和并发更新等问题。

2. 逻辑过期#

核心思想:缓存数据不立即物理删除,而是由应用程序判断业务过期时间。

处理流程:

  1. 从 Redis 读取缓存数据及逻辑过期时间。
  2. 如果未过期,直接返回数据。
  3. 如果已过期,尝试获取锁。
  4. 获得锁的线程异步查询数据库并重建缓存。
  5. 请求可以先返回旧数据,等待缓存更新。

特点:

  • 优点:请求通常不需要等待缓存重建,延迟较低。
  • 缺点:可能读取旧数据,需要处理异步重建失败。
  • 适用场景:允许短时间数据不一致的热点数据。

3. 两种方案对比#

对比项互斥锁逻辑过期
缓存失效后等待或重试先返回旧数据
数据新鲜度通常更偏向读取新数据允许短暂不一致
请求延迟可能较高通常较低
核心目标控制并发重建保证请求可快速返回

记忆:互斥锁是宁愿等一等,也要尽量读新数据;逻辑过期是宁愿暂时读旧数据,也不让请求一起冲击数据库。

四、面试回答速记#

1. 什么是缓存穿透?如何解决?

缓存穿透是指查询的数据在缓存和数据库中都不存在,导致请求每次都访问数据库。可以通过缓存空值或布隆过滤器解决。

2. 什么是缓存击穿?如何解决?

缓存击穿是指热点 Key 失效后,大量并发请求同时访问数据库。可以使用互斥锁控制缓存重建,或者使用逻辑过期,让请求先返回旧数据,再异步重建缓存。

3. 什么是缓存雪崩?如何解决?

缓存雪崩是指大量缓存 Key 同时失效,或者 Redis 整体不可用,导致大量请求冲击数据库。可以通过随机过期时间、Redis 高可用、限流、熔断和降级等措施解决。

4. 布隆过滤器的原理和缺点是什么?

布隆过滤器通过多个哈希函数将元素映射到位数组。查询时只要有一位为 0,就能确定元素不存在;所有位都为 1,则表示可能存在。其缺点是存在误判,标准实现不支持直接删除。

5. 互斥锁和逻辑过期有什么区别?

互斥锁控制只有一个线程重建缓存,其他请求等待或重试;逻辑过期保留旧数据,允许请求先读取旧数据,再由一个线程异步重建。前者偏向数据新鲜度,后者偏向低延迟。

缓存穿透、击穿、雪崩的区别与解决方案
https://blog.xqcherry.top/posts/interview/redis/redis-cache-penetration-breakdown-avalanche/
作者
xqcherry
发布于
2026-10-12
许可协议
CC BY-NC-SA 4.0