一,缓存穿透
1,概念
key对应的值在redis中不存在,这时针对key的请求从缓存获取不到,请求转发给数据库,访问量大了的话可能会压垮数据库。
2,解决方案
1)对空值缓存:如果一个查询的数据返回为空,我们仍然把这个空结果(null)存到缓存里面,这样可以缓解数据库的压力。设置空值缓存的过期时间很短,最长不超过5分钟(这样只能做为简单的应急方案)。
2)设置可访问的名单(白名单):使用bitmaps类型定义一个可以访问的名单,名单 id 作为 bitmaps 的偏移量,每次访问和 bitmap 里面的 id 进行比较,如果访问 id 不在 bitmaps 里面,进行拦截,不允许访问。
3)布隆过滤器:将所有可能存在的数据哈希到一个足够大的bitmaps中,一个一定不会存在的数据会被这个bitmaps过滤掉,从而避免了对底层存储系统的查询压力。
4)进行实时监控: 当发现 Redis 的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务。
二,缓存击穿
1,概念
key对应的数据存在,但在redis中过期,此时有大量并发请求访问该key,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大量的并发请求可能会瞬间把后端DB压垮。(redis某个热门数据过期,大量合理数据请求直接到达数据库)
2,解决方案
1)预先设置热门数据:在redis高峰访问之前,把一些热门的数据提前存入到redis里面,并加大过期时间。
2)实时调整:现场监控哪些数据热门,实时调整key的过期时间
3)使用锁:在缓存失效的时候(判断拿出来的值为空),不立即去查询数据库。先使用redis的某些带成功返回值的操作(比如,redis的SETNX方法)去set一个互斥锁 mutex key。当操作成功返回时,再进行查询数据库操作,并回设缓存,最后删除mutex key。当操作返回失败,说明有线程在查询数据库,当前线程睡眠一段时间再重试整个get缓存的方法。
三,缓存雪崩
1,概念
在极短的时间内大量的key过期,此时大量的请求落在这些key上面,当从redis中获取不到值的时候请求转发给数据库,数据库承受不住压力崩溃。
2,解决方案
1)构建多级缓存架构:nginx 缓存 + redis 缓存 +其他缓存(ehcache 等),程序设计较为复杂。
2)使用锁或队列:用加锁或消息队列的方式来保证不会有大量的线程对数据库一次性进行读写操作,从而避免key失效时,大量的并发请求落到数据库。但是这种方式影响性能,不适合高并发场景。
3)设置过期标志更新缓存:记录缓存数据是否过期,如果过期会触发通知另外的线程去后台更新实际key的缓存。
4)将缓存失效时间分散开:比如在原有的失效时间上增加一个随机数,1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的情况。