- Redis缓存的使用极大提高了应用程序的性能和效率,特别是在查询数据方面。但是同时,它也会带来一系列问题,其中,最要害的问题是数据一致性问题,从严格意义上来说,这个问题是无解的。如果对数据的一致性要求很高,那么就不能使用缓存。
1、缓存穿透
(1)什么是缓存穿透?
当用户想要查询一个数据,却发现redis内存中数据并没有存在,于是这时候需要向持久化层数据库中查询,发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,这时候都会去请求持久层的数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。
(2)解决方案
- 一个一定不存在缓存及查询不到的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。
解决方案:
对空值缓存:
如果一个查询返回的数据为空(不管是数据是否不存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟
设置可访问的名单(白名单):
- 使用bitmaps类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmap里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问。
采用布隆过滤器(Bloom Filter):
布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力
进行实时监控:
- 当发现Redis的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务
2、缓存击穿
(1)什么是缓存击穿?
key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
(2)解决方案
- key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题。
解决方法:
预先设置热门数据:
- 在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的时长
实时调整:
- 现场监控哪些数据热门,实时调整key的过期时长
加互斥锁:
3、缓存雪崩
(1)什么是缓存雪崩?
key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
缓存雪崩与缓存击穿的区别在于这里针对很多key缓存,前者则是某一个key
- 正常访问
- 缓存失效瞬间
(2)解决方案
解决方法:
- 构建多级缓存架构:
- nginx缓存 + redis缓存 +其他缓存(ehcache等)
- 使用锁或队列:
- 用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。不适用高并发情况
- Redis高可用:
- 多增设几台redis,这样一台挂掉之后其它的还可以继续工作,其实就是搭建redis集群
- 数据预热:
- 在正式部署之前,可以先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中,在即将发生大并发访问前手动触动加载缓存不同的key,设置不同的过期时间,让缓存失效时间点尽量均匀