在实际工程中,Redis 缓存问题常伴随高并发场景出现。例如,电商大促、活动报名、突发新闻时,由于缓存失效导致大量请求访问数据库,导致雪崩、击穿、穿透等问题。因此,新系统上线前需预热缓存,以应对高并发,减轻数据库压力。本章主要围绕这几个核心问题,针对产生场景、分析原因、并给出相应的解决方案。
常见问题:

1. 缓存穿透
1.1 什么是缓存穿透
一句话,就是查询一条根本没有的记录。它既不存在于redis中,也不存在数据库中。一般我们的查询顺序是先查redis、再查数据库。每次请求最终都会访问到数据库。造成数据库访问压力。这种现象叫缓存穿透。
问题描述
key 对应的数据在数据源并不存在,每次针对此 key 的请求从缓存获取不到,请求都会压到数据源(数据库),从而可能压垮数据源。比如用一个不存在的用户 id 获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。
1.2 产生原因
-
查询记录在redis和数据库均不存在
-
恶意攻击
缓存穿透发生的条件:
- 应用服务器压力变大
- redis 命中率降低
- 一直查询数据库,使得数据库压力太大而压垮
其实 redis 在这个过程中一直平稳运行,崩溃的是我们的数据库(如 MySQL)。
缓存穿透发生的原因:黑客或者其他非正常用户频繁进行很多非正常的 url 访问,使得 redis 查询不到数据库。
1.3 解决方案
方案一:使用布隆过滤器
使用布隆过滤器解决缓存穿透问题具体流程如下:

流程说明:
-
Web端发起请求到App服务应用
-
经过布隆过滤器判断key是否存在
-
若不存在,直接返回null
-
若key存在或者被误判(下文详述),查询redis
-
若redis中有结果,直接返回
-
未查到,则查询数据库返回结果
-
数据库查到结果,返回结果。并将对应key回写redis
-
未查到,则返回null
方案二:缓存空对象或者默认值
针对要查询的数据,需求层面沟通,可以在Redis里存一个缺省值(比如,零、负数、defaultNull等)。

流程描述:
-
先去redis查键user:xxxxxx没有,再去mysql查没有获得 ,这就发生了一次穿透现象;
-
第一次来查询user:xxxxxx,redis和mysql都没有,返回null给调用者;
-
将 user:xxxxxx,defaultNull 回写redis;
-
第二次查user:xxxxxx,此时redis就有值了。
可以直接从Redis中读取default缺省值返回给业务应用程序,避免了把大量请求发送给mysql处理,打爆mysql。
但是,此方法只能解决key相同的情况,但是无法应对黑客恶意攻击。
解决方案:
- 对空值缓存:如果一个查询返回的数据为空(不管是数据是否不存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟。
- 设置可访问的名单(白名单):使用 bitmaps 类型定义一个可以访问的名单,名单 id 作为 bitmaps 的偏移量,每次访问和 bitmap 里面的 id 进行比较,如果访问 id 不在 bitmaps 里面,进行拦截,不允许访问。
- 采用布隆过滤器:布隆过滤器(Bloom Filter)是 1970 年由布隆提出的。它实际上是一个很长的二进制向量 (位图) 和一系列随机映射函数(哈希函数)。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
- 进行实时监控:当发现 Redis 的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务。
2. 缓存击穿
2.1 什么是缓存击穿
一句话,就是热点key突然失效了,大量请求暴击数据库。关键词:大量请求、同一个热点key、正好失效。
问题描述
key 对应的数据存在,但在 redis 中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端数据库加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端数据库压垮。
2.2 产生原因(发生场景)
-
某个key以到过期时间,但是还是被访问到
-
key被删除,但是被访问到
-
如,某电商网站的今日特卖
缓存击穿
Redis缓存问题及其解决方案:雪崩、击穿、穿透与预热

本文详细讨论了Redis缓存中遇到的常见问题,如缓存穿透、击穿和雪崩,分析了其产生的原因,并提供了布隆过滤器、互斥锁等解决方案,以及缓存预热策略,以提升系统性能和应对高并发场景。
最低0.47元/天 解锁文章
1417

被折叠的 条评论
为什么被折叠?



