缓存穿透、缓存击穿、缓存雪崩区别和解决方案
缓存处理流程
前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果。
缓存穿透
描述:
缓存穿透是指用户对缓存和数据库中都没有的数据不断发起请求,比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,这时的用户很可能是攻击者,攻击会导致数据库压力过大。
解决方案:
-
对空值缓存:如果一个查询返回的数据为空(不管是数据是否不存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟,这样可以防止攻击用户反复用同一个id暴力攻击。
-
设置可访问的名单(白名单):
使用bitmaps类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmap里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问。
-
采用布隆过滤器:布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。将所有可能存在的数据哈希到一个足够大的bitmaps中,一个一定不存在的数据会被 这个bitmaps拦截掉,从而避免了对底层存储系统的查询压力。
-
进行实时监控:当发现Redis的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务。
缓存击穿
描述:
缓存击穿是指某个 key 对应的数据在后端数据库中存在,但在redis缓存中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端数据库加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端数据库压垮。一般都是由于某个 key 刚好过期了,而此时突然有大量的访问使用这个 key。
解决方案:
-
预先设置热门数据:在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的时长。
-
实时调整:现场监控哪些数据热门,实时调整key的过期时长。
-
加互斥锁:流程如下图所示
缓存雪崩
描述:
缓存雪崩是指缓存中数据大批量过期,而查询数据量巨大,引起数据库压力过大甚至down机。
与缓存击穿的区别:
缓存击穿指在某一极小时间段内,对同一过期数据的大量访问;(大量请求都访问某一个过期的key)
缓存雪崩指在某一极小时间段内,对很多已过期的不同数据的大量访问;(大量请求都访问某一批过期的key)
这是一个缓存雪崩的例子:https://geektutu.com/post/geecache-day4.html#1-2-节点数量变化了怎么办?
解决方案:
-
将缓存过期的时间分散开:
比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,防止同一时间大量数据过期现象发生。
-
构建多级缓存架构:nginx缓存 + redis缓存 +其他缓存(ehcache等)
-
设置过期标志更新缓存:
记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际key的缓存。