Redis的缓存击穿、雪崩、穿透问题是我们日常开发中必须考虑到的问题,本文通过对它们出现的常见情况以及相应的解决方案对其进行逐一分析。
一.缓存击穿
Redis的某个Key突然失效,导致该Kye的所有并发请求都直达MySql,并发请求量过大导致Mysql性能下降,出现宕机,进而蔓延到整个系统无法使用。
出现场景:
Redis里面有一个key,它正在承担3000个请求的并发量,Mysql通常只能支持2000个并发量,,那么如果说我们Redis里面的这个Key,突然出现失效,也就代表它的过期时间已经归零了(TTL等于0),那么这时候这个key根据Redis的内存淘汰机制和过期策略,Redis就会将这个Key进行删除掉,那么这3000个请求就会瞬息来带Mysql,3000请求大约Mysql的2000请求,就可能导致Mysql出现瞬间宕机,导致整个系统都没办法进行使用。
解决方案:
1.合理的过期时间:将热点数据设置为用不过期,又或者及时将这个Key及时续期,将它的TTL时间进行延长;
2.使用互斥锁:我们可以基于zookeeper实现一个互斥锁,等到第一个请求构建缓存之后,在释放锁,进而其他请求就能通过Redis获取Key的数据进行返回了,大量的请求就不会到达Mysql,也就不会导致宕机的情况出现。
二.缓存雪崩
Redis的多个Key出现失效,导致多个Kye的并发请求都直达MySql,并发请求量过大导致Mysql性能下降,出现宕机,进而蔓延到整个系统无法使用。
出现场景:
Redis里面有多个Key出现同时失效,那么这些Key的请求都到达了Mysql,虽然它的某个Key的并发请求数量没有击穿的这个Key上面的数量多,但是经不住它是多个Key同时失效,那么这些Key上面的请求数汇总过来就可能导致Mysql出现性能下降,从而出现宕机。
解决方案:
1.将Redis进行高可用的部署(主从+哨兵、Redis集群),避免Redis出现全盘崩溃;
2.可以使用本地缓存和hystrix限流降级操作,避免Mysql被打死,同时也可以根据Redis的Key设置一个合理的过期时间,避免大量的Key同时失效,避免大量的请求到达Mysql。
三.缓存穿透
请求的Key在Redis和Mysql中均不存在, 导致多个不存在Kye的并发请求都直达MySql,并发请求量过大导致Mysql性能下降,出现宕机,进而蔓延到整个系统无法使用。
出现场景:
缓存穿透和缓存击穿、雪崩又有一点不同,它其实是用户或者一个恶意的访问者构建了一个不存在的Key,也就是在Redis里面不存在的数据,同时在Mysql里面也不存在该数据,因此大量的请求并没有通过Redis来进行访问数据,而是直接到达的Mysql,等同于Redis的缓存不存在,导致Mysql宕机,但是这种常见是比较少的,但是也不能够排除。
解决方案:
1.缓存空对象:对于查询结果为空的情况,也将其缓存起来,并设置合理的过期时间(针对这些恶意构建的Key,虽然我们在Redis和Mysql里面都确实不存在这样的数据,但是我们可以针对这种Key,设置Redis里面缓存一个相应的空值,这样大量的请求就不会到达Mysql里面,直接通过Redis放回一个空值给请求方,但是需要设置一个合理的过期时间,因为有的时候我们确实有的场景是该数据在Redis和Mysql里面不存在,但是随着系统的运行,这部分数据可能会产生,因此我们要设置一个合理的过期时间,当这个时间过了以后,这个Key就会被删除掉,当用户正常访问的时候,这个Key就会被重新缓存到Redis里面,提供用户访问);
2.参数校验:在接受到请求之前进行参数校验,判断请求是否合法(缓存空对象这其实是一种理想的情况,如果说我们的这个Key确实是恶意请求,那么就可以通过参数校验进行处理,在请求之前校验这个Key是否合法,如果不合法,就直接打回,不做任何处理);
3.布隆过滤器:判断请求的参数是否存在于Redis或Mysql中(也是判断参数是否合法,不合法就打回,阻止恶意参数的请求进入到系统中)。