Redis缓存穿透、击穿和雪崩
参考资料
苏三说技术:烂大街的缓存穿透、缓存击穿和缓存雪崩,你真的懂了?
🙋关键要点
- 缓存的目的与常见使用方案,分布式缓存介绍;
- 缓存穿透的概念、解决方案,介绍布隆过滤器;;
- 缓存击穿的概念、解决方案;
- 缓存雪崩的概念、解决方案;
- 三个常见分布式缓存问题的区别;
- 其它分布式缓存的相关概念,三种缓存淘汰策略;
- 分布式缓存的应用。
🙋正文
- 📌 缓存的目的是什么?
减轻数据库压力,提高系统性能。
- 📌 缓存的常见使用方案是什么?
适用于查询配置信息请求, 先查询缓存,如果存在数据,直接返回;
不存在数据,则从数据库查找,数据存在则放入缓存。
- 📌 什么是分布式缓存?
指将缓存数据,分布在多个节点上的缓存系统,从而实现在多台服务器之间共享和存储数据,这就是分布式缓存。能够提升系统性能、降低数据库负载,并支持高并发访问。
- 📌 什么是缓存穿透(Cache Penetration)?
- 定义
指查询的数据在缓存和数据库中都不存在,导致所有请求直接打到数据库,当恶意或者频繁发起请求,会造成数据库压力骤增甚至宕机的情况。
- 什么引起缓存穿透
用户请求id在缓存中不存在,恶意用户伪造不存在的id发起请求(如 userId=-1
或超大 id
)
- 如何防止缓存穿透?
✅ 参数校验(避免无效请求)
对ID进行格式校验,避免非法值直接查询数据库。
✅ 访问控制与限流
对同个IP或者用户的高频查询做限流。
如单位时间内访问相同 key 超过 1000 次,则封禁 IP 或降低查询频率。
✅ 布隆过滤器(Bloom Filter) 🚀(推荐用于大规模数据)
数据少的情况下,可以把数据库的数据放在一个map里面,这样能够快速的识别数据在缓存中是否存在。
如果数据量大,都放到内存里面就会占用太多的内存空间。此时就需要引入布隆过滤器。 查询前,先检查布隆过滤器,如果数据一定不存在,就不查询数据库。
- 什么是布隆过滤器
布隆过滤器是一种**空间高效的概率性数据结构,用于判断某个值是否可能存在**。由于可能误判,则其适用于大规模但不需要精确查询的数据。
- 布隆过滤器查询的原理
底层: 使用bit数组存储数据,该数组中的元素默认值是0。
组成: 由一个位数组(bit array) 和 多个哈希函数(hash functions) 组成。
插入和查询的操作: 当插入元素会经过多个哈希计算,将对应bit位置置为1,查询时,只需要检查是否全为1。
检查是否存在:
如果所有对应的 bit 位都是 1:可能存在(但可能是误判)。
如果有任意一个 bit 位是 0:一定不存在(绝对准确)。
- 布隆过滤器的优缺点
优点是:存储空间很小,比哈希表小得多(哈希表要存储一整个key)
缺点是: 可能误判(但不会漏判,误判是因为哈希冲突),其次不支持删除元素,只能重建
- 如何减少误判概率
可以适当增加hash函数。
因为布隆过滤器第一次初始化的时候,会把数据库中所有已存在的key,经过一些列的hash算法(比如:三次hash算法)计算,每个key都会计算出多个位置,然后把这些位置上的元素值设置成1。
✅ 缓存空值(推荐)
通常情况下很少用布隆过滤器解决缓存穿透问题。
缓存空值的做法是,在数据库中也查不到时,也将该用户id缓存起来,只不过值是空的。后面请求时就会从缓存中获取空数据,不需要查询数据库。
- 📌 什么是缓存击穿(Cache Breakdown)?
- 定义
指某个热点数据在缓存中过期,但在短时间内有大量并发请求访问该数据,导致这些请求直接打到数据库,造成数据库压力骤增甚至宕机的情况。
- 解决方案
✅ 让热点数据“永不过期”
针对热点数据,设置超长 TTL(Time To Live)或直接不设置过期时间,避免缓存过期导致的数据库访问激增。
比如限时抽奖或者秒杀活动,可以将过期的时间设置为活动结束后一天等。
或者提前从数据库中查询商品数据并同步缓存到数据库,提前预热数据,等到活动结束将手动删除无用的缓存。
✅ 互斥锁(Mutex)机制(防止瞬间高并发击穿)
当缓存失效时,第一个请求获取数据库数据,并加锁,防止其他请求同时查询数据库。
数据库压力过大的根源是同一时间太多请求访问数据库;此时的解决方案设置为限制访问。
✅ 定时续期
用定时任务每隔一段时间就重新设置过期时间,比如job每隔20分钟执行一次,自动更新缓存,重新设置过期时间为30分钟。
❌但是该方案的局限性是, 如果有大量热点key定时任务的负担会变重,限制系统性能;若是缓存服务器down掉或者key被手动删除,还是会触发数据库查询。
- 什么是热key?
热点key是指缓存中被频繁访问的key,导致缓存该key的分片或者redis访问量过高。
- 📌 什么是缓存雪崩(Cache Avalanche)?
- 描述的是什么情况
指在短时间内**大量热门缓存数据同时失效或者缓存服务器down机**,导致大量的请求直接读取到下游数据库,严重时会导致数据库宕机,无法提供数据服务,导致系统崩溃。
- 跟缓存击穿的关系
可以理解为缓存击穿的一个热key失效,而缓存雪崩是多个热key同时失效。
- 如何防止缓存雪崩?
✅缓存过期时间加“随机抖动”
避免大量数据在同个时间过期,给不同key不同的过期时间,或在过期时间基础上增加随机值。例如:
EXPIRE key (60 + random(10)) # 设置过期时间 60-70 秒之间
✅ 限流与降级
做好限级限流的策略;
可以基于ZooKeeper等实现活动降级。在缓存失效时,可以返回默认数据或降级数据,避免直接请求数据库。
✅ 使用Redis集群。当有节点宕机时使用其他节点恢复数据
✅ 构建多级缓存架构
- 以上三个分布式缓存常见问题的区别是什么?
问题 | 定义 | 原因 | 影响 | 解决方案 |
---|---|---|---|---|
缓存穿透(Cache Penetration) | 频繁查询缓存和数据库都没有的数据,导致所有请求都落到数据库 | 恶意攻击或查询不存在的数据 | 数据库压力激增,可能导致宕机 | 布隆过滤器、缓存空值等 |
缓存击穿(Cache Breakdown) | 某个热点 Key 过期,导致大量并发请求同时访问数据库 | 热点数据过期瞬间,多个请求同时查询数据库 | 数据库瞬间压力过大 | 互斥锁(分布式锁) 、设置不过期等。 |
缓存雪崩(Cache Avalanche) | 大量 Key 同时过期,导致缓存失效,所有请求打到数据库 | 大量数据同时到期或Redis 故障 | 数据库被大量请求压垮 | 缓存过期时间加“随机抖动” 、多级缓存、限流降级等 |
- 📌 缓存的其它概念
① 缓存预热
系统上线后,将相关的缓存数据直接加载到缓存系统。
比如在一个抽奖活动中,将活动、奖品等配置信息缓存到redis中。在首次查询时,缓存中不存在,则在数据库中查询,查询到的结果缓存到redis。
② 缓存淘汰策略
- 为什么需要缓存淘汰
缓存数据过多,要用淘汰策略决定淘汰哪些数据。
- 常见的淘汰算法
FIFO(First In First Out) :先进先出算法,判断存储时间,离当前时间越久的数据越有限被淘汰。
LRU(Least Recently Used) :最近最少使用算法,判断缓存最近被使用的时间,距离当前时间越远的数据优先被淘汰。
LFU(Least Frequently Used): 最不经常使用算法,在一段时间内被使用次数最少的数据缓存优先被淘汰。
- 📌 分布式缓存应用场景举例
- 数据库查询缓存: 减少数据库压力,提高查询性能
- 分布式锁:通过 Redis 等缓存系统实现分布式锁,以保证在分布式系统中多个进程或线程对共享资源的互斥访问,
- 排行榜:其数据一般是热点数据、需要进行动态排序,如果一直依赖数据库会导致性能瓶颈;且如果排行榜访问量很高,数据库每次都查询最新排名、计算排名,就可能导致数据库崩溃(即缓存雪崩)。利用 Redis 的
ZSET
(有序集合)实现排行榜功能,支持按分数排序,减少数据库频繁计算,如电商热销商品排行、游戏玩家积分排行等。