缓存
- 引言
- 经典应用场景
- 缓存的"三大坑"
-
- [1. 缓存穿透(查不到)](#1. 缓存穿透(查不到))
- [2. 缓存击穿(热点 Key 过期)](#2. 缓存击穿(热点 Key 过期))
- [3. 缓存雪崩(集体失效)](#3. 缓存雪崩(集体失效))
- 结语
引言
既然我们已经通过哨兵和集群保证了 Redis 的稳定性,那么接下来就要关注它作为缓存时的业务逻辑了。
Redis 的核心思想其实很简单:在应用和数据库之间引入一个基于内存的中间层。由于内存的读写速度远超磁盘,这层中间件能拦截掉绝大部分对数据库的直接访问,极大地减轻后端压力。然而,这种架构在带来高性能的同时,也引入了新的挑战。
在高并发场景下,如果缓存策略设计不当,很容易遭遇三个经典问题:缓存雪崩、缓存穿透、缓存击穿。它们会导致大量请求直接"穿透"缓存层,瞬间压垮数据库。
首先我们先来看看Redis的经典使用场景~
经典应用场景
Redis 不仅仅是简单的键值存储,利用它的不同数据结构,我们可以解决很多特定场景的问题:
- 页面缓存: 对于商品详情页、新闻文章页这种读多写少的页面,我们可以把整个 HTML 片段或者渲染后的数据存入 Redis。用户访问时直接读取,避免了复杂的后端逻辑计算和数据库查询。
- 会话(Session)存储: 在分布式系统中,用户的登录状态(Session)如果存在单台服务器内存里,会导致负载均衡时用户频繁掉登录。把 Session 存入 Redis,所有应用服务器共享一份 Session 数据,完美解决这个问题。
- 计数器: Redis 的原子性操作(如
INCR)非常适合做计数器,比如文章的阅读量、微博的点赞数、商品的销量排行。即使并发量再大,也不会出现数据错乱。 - 分布式锁: 在集群环境下,为了防止多个节点同时操作同一份数据导致脏写,我们需要一个全局的"锁"。Redis 的
SETNX命令(SET if Not eXists)是实现分布式锁的常用手段。
缓存的"三大坑"
虽然缓存能提升性能,但如果使用不当,也会带来灾难性的后果。在生产环境中,你必须警惕以下三个经典问题:
1. 缓存穿透(查不到)
- 现象: 指查询一个一定不存在的数据(比如黑客攻击,用大量不存在的 ID 恶意请求)。
- 后果: 缓存层查不到,请求全部打到数据库层,可能导致数据库瞬间压力过大甚至宕机。
- 解决方案:
- 布隆过滤器(Bloom Filter): 在请求到达数据库前,先用布隆过滤器拦截掉不存在的 Key。
- 缓存空值: 即使数据库查不到,也在 Redis 里存一个空值(
null),并设置较短的过期时间(如 5 分钟),防止同一无效 Key 反复攻击。
2. 缓存击穿(热点 Key 过期)
- 现象: 某个热点 Key(比如爆款商品)在某一时刻正好过期失效。
- 后果: 瞬间涌入的大量并发请求全部落到数据库上,造成"穿刺"效果。
- 解决方案:
- 互斥锁(Mutex): 当缓存失效时,不是直接让所有请求都去查数据库,而是只允许一个线程去重建缓存,其他线程等待并重试缓存。
- 逻辑过期: 不设置 Redis 的物理过期时间,而是把过期时间存在缓存的 Value 里。查询时判断逻辑时间,如果过期则异步起线程去更新,当前请求依然返回旧值。
3. 缓存雪崩(集体失效)
- 现象: 指在某一时刻,大量的缓存数据集体失效(比如缓存服务重启,或者大量 Key 设置了相同的过期时间)。
- 后果: 数据库瞬间承受全量请求,直接被压垮。
- 解决方案:
- 过期时间加随机值: 在设置缓存过期时间时,增加一个随机数(例如:基础时间 30 分钟 + 0~5 分钟的随机数),让 Key 的失效时间分散开来。
- 高可用架构: 也就是我们之前讲的,使用 Redis 集群或哨兵,保证缓存服务本身不挂。
结语
学到这里你就会发现计算机的尽头是架构,我们要努力的提升自己的架构思维,才能真正的把技术服务于业务,希望和大家一起加油!