一、缓存穿透
如上图,正常情况下,如果用户在redis缓存中没有查询到自己想要的数据,就会去mysql数据库中查询。如果mysql数据库中也没有,在没有任何措施下,用户一定会不断的去mysql数据库中查询,随着时间的推移,用户越来越多,越来越多的用户在redis缓存中没有查询到自己想要的数据,越来越多的用户就会去mysql数据库中查询,这就造成了缓存穿透。
解决方案:
1、使用布隆过滤器
“过滤器”这个名词做过项目的人应该很熟悉,而对于redis缓存穿透而言,使用“布隆过滤器”就是解决方案之一。
后台服务端可以在用户和redis数据库之间搭上一个“过滤器”,在用户访问redis之前,通过布隆过滤器,如果用户想访问的数据在redis数据库中没有的话,就使用布隆过滤器将用户的这次访问给过滤掉,这样的话用户就不会再去访问mysql数据库了,很好的解决了缓存穿透。
2、redis缓存空值(占空间,没意义,不建议)
当用户访问redis的时候,如果说用户访问的数据在redis中没有,那就根据用户访问的“key”给用户在redis中缓存一个空的“value”,这样的话用户就不用再去访问mysql数据库了。
这种方法也是解决缓存穿透的一种方案,但是不建议。因为在redis中缓存一个空的value,一方面占了redis数据库的空间(redis数据库的数据是存在内存中的,而内存又有限),另一方面给一个key缓存一个空的value也没有什么意义,而且还浪费数据库开销,所以这种方案不建议。
二、缓存击穿
当某一个“key”的热度非常高,肯定就会有很多的人根据这个“key”去redis中查询对应的“value”。
刚才也说过,因为redis数据是存在内存中的,内存又有限,所以redis会对于一些数据设置过期时间,一到时间,这些key就会过期消失。
所以如果当某个热度很高的“key”在redis中过期了,那么这些用户肯定会集体的去访问mysql数据库(就像一颗颗子弹,全部都打到了一个点上),因此就造成了缓存击穿。
缓存击穿和缓存穿透很像,但是还是有一些区别的。
解决方案:
1、设置热点数据永不过期
这是一个很绝的方案,可以完美的解决缓存击穿。
但是不建议,因为redis本就内存有限,热点数据越来越多,无疑就会撑满redis,导致redis的性能下降。总的来说就是“占空间”。
2、加互斥锁
某个热点“key”突然失效过期,用户们在redis中访问无果,肯定会集体去mysql访问。
而在用户们访问mysql之间就可以加一道锁,来解决缓存击穿。
加锁只保证一个线程可以进去,这样的话就可以解决大量的用户去mysql访问同一个数据。
三、缓存雪崩
缓存雪崩是最好理解的,雪崩的场景大家肯定都不陌生。
当某个时间段,redis缓存中的“key”集体失效(可以理解为redis宕机),那么用户查不到这些“key”对应的“value”,就肯定会集体的向mysql数据库中查询,这样大面积的访问,就造成了缓存雪崩。
和缓存击穿很像,但是又不一样,缓存击穿是大量的用户去mysql中查询同一个“key”对应的“value”,而缓存雪崩是大量的用户去mysql中查询不同“key”对应的“value”。
解决方案:
1、实现redis高可用
搭建redis集群,配置redis哨兵机制,实现redis高可用。
主机宕机之后,通过redis哨兵机制去自动的在从机中重新选取主机,实现redis的高可用,解决缓存雪崩。
2、数据预热
可以把可能会大量访问的数据预先访问一遍,然后在加载到缓存中,最后再给它们设置不同的缓存过期时间,让缓存失效的时间点尽量均匀一些。这也是解决缓存雪崩的一种方案。