Redis——缓存

说说缓存穿透,缓存击穿,缓存雪崩

  • 缓存穿透:查了一个压根就不存在的数据(比如查 ID=-1),缓存没命中,数据库也没命中,导致每次请求都直接打在数据库上。
  • 缓存击穿:某个热点数据(比如微博热搜第一名)刚好过期了,瞬间海量请求直接打在数据库上。
  • 缓存雪崩:一大波数据同时过期,或者缓存服务直接挂了,导致所有请求像雪崩一样涌向数据库。

🕳️ 缓存穿透 (Cache Penetration)

核心特征:查询的数据在缓存和数据库中都不存在。

1. 场景还原

想象你是一个图书管理员(数据库),门口有个助手(缓存)。

有个捣蛋鬼一直问你:"有没有《哈利波特与量子力学》这本书?"

  • 助手查了一下目录(缓存),说:"没有。"
  • 捣蛋鬼不信,非要你进库房(数据库)查。
  • 你进库房查了一圈,确实没有。
  • 结果:因为库房里确实没这本书,你没法把这本书的信息告诉助手(无法回写缓存)。捣蛋鬼过一秒又问一遍,你只能再跑一趟库房。如果有一万个捣蛋鬼同时问不存在的书,你的库房大门会被挤爆。
2. 常见原因
  • 恶意攻击:黑客故意构造不存在的 ID(如 -1, null, 随机 UUID)发起请求。
  • 业务漏洞:前端传参错误,或者数据未同步。
3. 解决方案
  • 方案一:缓存空对象(最常用)
    • 做法:当数据库查询为空时,依然把这个"空结果"写入缓存(比如存个 null 或特定字符串),并设置一个较短的过期时间(如 5 分钟)。
      • 效果:下次请求到缓存后直接返回,不需要再访问数据库。
  • 方案二:布隆过滤器(布隆过滤器是一种空间效率极高的概率性数据结构,用于快速判断一个元素是否在一个集合中。)
    • 做法:在请求到达缓存之前,先过一个"安检门"(布隆过滤器)。它告诉你这个 ID 可能存在 或者 一定不存在。
    • 效果:如果布隆过滤器说"一定不存在",直接拦截,连缓存和数据库都不用查。

🔨 缓存击穿 (Cache Breakdown)

核心特征单个热点 Key 突然过期,高并发瞬间击穿。

1. 场景还原

还是那个图书管理员。

有一本《三体》特别火,大家都在看助手手里的复印件(缓存)。

  • 突然,复印件过期失效了(Key 过期)。
  • 这一瞬间,正好有 1 万个读者涌进来要看书。
  • 大家发现助手没书了,于是 1 万人同时冲向库房(数据库)找你要原书。
  • 结果:库房瞬间被挤爆,甚至导致数据库宕机。
2. 常见原因
  • 热点数据:秒杀商品、微博热搜、突发新闻。
  • 时间巧合:正好在访问高峰期,该数据的 TTL(生存时间)到了。
3. 解决方案
  • 方案一:互斥锁(Mutex Lock)
    • 做法:当发现缓存失效时,不要所有人都去查数据库。大家先抢一把锁(比如 Redis 的 setnx)。
    • 效果:只有抢到锁的那 1 个人去查数据库并回写缓存,其他 9999 个人在门外等着(或者重试),等缓存写好了,他们直接从缓存读。
  • 方案二:逻辑过期
    • 做法:物理上不给缓存设置过期时间(永不过期),但在数据里存一个"逻辑过期时间戳"。
    • 效果:读取时发现逻辑过期了,先返回旧数据(保证可用性),同时开启一个异步线程去后台更新数据。

🏔️ 缓存雪崩 (Cache Avalanche)

核心特征:大量 Key 同时过期 或 缓存服务宕机。

1. 场景还原
  • 情况 A(同时过期):你为了省事,给库房里所有书的复印件都设置了"今晚 12 点过期"。结果 12 点一到,所有读者的复印件全失效了,所有人同时冲向库房。
  • 情况 B(服务宕机):助手(Redis)突然累倒了(宕机),没法提供服务。所有读者只能直接冲进库房找你。
  • 结果:这种流量冲击像雪崩一样,瞬间压垮数据库。
2. 常见原因
  • 批量设置过期时间:代码里写死了 expireTime = 24h,导致所有数据在同一时刻失效。
  • Redis 故障:服务器断电、网络中断、内存溢出导致 Redis 挂掉。
3. 解决方案
  • 方案一:过期时间随机化
    • 做法:在原有的过期时间基础上,加一个随机值。比如 基础时间 + 随机(0, 300秒)
    • 效果:让 Key 的过期时间分散开,避免"扎堆"失效。
  • 方案二:高可用架构
    • 做法:部署 Redis 哨兵(Sentinel)或集群(Cluster)。
    • 效果:主节点挂了,从节点立马顶上,实现自动故障转移,保证缓存服务不中断。
  • 方案三:限流降级
    • 做法:当数据库压力过大时,直接拒绝部分请求,或者返回默认值(比如"系统繁忙"),保住数据库的命。

本地缓存和Redis的区别了解吗?

本地缓存存在应用进程内,性能极高但多实例数据不一致、容量有限;Redis 是分布式缓存,数据全局一致、容量可扩展,但有网络开销;

本地缓存适合热点数据兜底、高性能要求的场景;对于读取频率极高、数据相对稳定、允许短暂不一致的数据,我优先选择本地缓存。Redis 适合分布式共享、海量数据、复杂操作的场景;对于需要实时同步、数据变化频繁、多个服务需要共享的数据,我会选择 Redis。

生产环境通常用「本地缓存 + Redis」多级架构,既保证性能,又保证一致性和可用性。

Redis 可以部署在多个节点上,支持数据分片、主从复制和集群。而本地缓存只能在单个服务器上使用。

1. 本地缓存适用场景
  • 热点数据兜底:比如秒杀场景,将爆款商品缓存到本地,防止 Redis 宕机导致缓存雪崩;
  • 高频读、低频写的静态数据:如地区编码、字典表、接口固定配置;
  • 性能极致要求的场景:如核心接口响应时间要求 < 10ms,本地缓存可减少网络耗时;
  • 分布式缓存的前置缓存:先查本地缓存,未命中再查 Redis,减少 Redis 请求量。
2. Redis 缓存适用场景
  • 分布式场景:多应用实例共享缓存(如用户登录态、购物车);
  • 海量数据缓存:超出单机内存容量的缓存(如商品列表、订单记录);
  • 需要复杂操作的场景:分布式锁、限流、排行榜、计数器(如点赞数统计);
  • 数据一致性要求高的场景:如商品价格、库存,需全局统一的缓存值。
3. 本地缓存数据不一致怎么解决?

① 设置极短过期时间(如 1 分钟),兜底数据一致性;② 核心数据更新时,通过 MQ / 事件通知所有实例更新本地缓存;③ 禁用本地缓存的写操作,仅通过 Redis 回写。

来说说你们项目里的缓存设计,怎么保证性能、一致性和高可用?

我们项目采用本地缓存加 Redis 二级缓存架构。系统启动和大促前会做缓存预热,避免冷启动压力。更新采用先更库、再删缓存的策略,配合过期时间和 Canal 保证最终一致。针对穿透、击穿、雪崩,分别用布隆过滤器、分布式锁、过期时间打散来防护。同时做了限流、降级、多级缓存兜底,保证在极端情况下核心业务依然可用。

具体如下:

一、整体架构:多级缓存设计

我们项目采用 本地缓存(Caffeine)+ 分布式缓存(Redis) 两级缓存架构:

  1. 读请求优先查本地缓存
    • 速度最快,减少 Redis 压力
  2. 本地未命中再查 Redis
  3. Redis 未命中再查数据库
  4. 查到后回写到 Redis + 本地缓存

目的:

  • 抗更高并发
  • 降低 Redis 网络开销
  • Redis 故障时本地缓存可以兜底,防止雪崩

二、缓存预热(冷启动保护)

为了避免系统刚上线或 Redis 重启后,大量请求直接打穿数据库,我们做了缓存预热:

  1. 项目启动时预热
    • ApplicationRunner 在服务启动完成后,加载字典、配置、热点商品、类目等基础数据
  2. 定时预热
    • 每天凌晨通过定时任务刷新静态数据缓存
  3. 大促手动预热
    • 提供后台管理接口,手动触发秒杀商品、活动页缓存预热
  4. 分批加载
    • 避免一次性加载太多数据导致启动慢、数据库压力大

预热后,系统一上线就能直接读缓存,不会出现冷启动性能尖刺。


三、缓存更新策略(保证一致性)

我们采用 Cache Aside 模式,这是业界最成熟、最推荐的方案:

  1. 查询:命中即返回,未命中查库并回填缓存
  2. 更新:先更新数据库,再删除缓存
    • 不更新缓存,避免并发覆盖问题
    • 删除缓存后,下一次查询自动拉最新数据

为了保证极端场景下的一致性:

  • 给缓存加过期时间兜底
  • 关键数据通过 Canal 监听 binlog 异步删除缓存,确保最终一致

四、缓存三大问题防护(穿透、击穿、雪崩)

1. 缓存穿透
  • 前端 + 后端参数校验,过滤非法 ID
  • 对不存在的数据缓存空值,并设置短过期
  • 高并发恶意攻击场景使用布隆过滤器拦截
2. 缓存击穿
  • 秒杀、热点商品设置永不过期
  • 并发查询用分布式锁,只允许一个请求去查数据库
3. 缓存雪崩
  • 过期时间加随机值打散,避免同时失效
  • 多级缓存兜底
  • Redis 使用哨兵 / 集群保证高可用
  • 接口做限流 + 降级,保护数据库

五、缓存降级与兜底(高可用保障)

极端情况比如:

  • Redis 集群宕机
  • 网络抖动
  • 数据库压力过大

我们会启用缓存降级策略:

  1. 核心接口直接返回本地缓存旧数据,保证可用
  2. 非核心接口直接返回默认值 / 静态页面
  3. 限流放开,避免流量压垮服务
  4. 监控告警,自动或人工恢复后关闭降级

保证核心业务可用,不雪崩、不宕机。

相关推荐
二月夜2 小时前
Maven 常用命令完整版速查表
java·maven
砍材农夫2 小时前
spring-ai 第十tool调用
java·人工智能·spring
aaa最北边2 小时前
计算机网络-断开连接的四次挥手底层细节
java·网络·计算机网络
java叶新东老师2 小时前
解决jetbrains idea 自带终端无法加载windows系统环境变量
java·windows·intellij-idea
大G的笔记本2 小时前
Java WebSocket客户端--java.net.http.HttpClient
java·websocket·.net
我是李龙2 小时前
第二十一章 项目启动与治理架构:从招标到甲乙方协作机制的建立
java·架构·devops
Mem0rin2 小时前
[Java/数据结构]树的基本概念、二叉树的创建和遍历
java·开发语言·数据结构
rannn_1112 小时前
【Redis|高级篇2】多级缓存|JVM进程缓存、Lua语法、多级缓存实现(OpenResty)、缓存同步(Canal)
java·redis·分布式·后端·缓存·lua·openresty
Lyyaoo.2 小时前
【JAVA基础面经】CAS 与 ABA
java·开发语言