原来解决Redis击穿、雪崩、穿透真的不是那么简单的一件事!!(缓存穿透)
一、缓存穿透
之前两篇文章已经介绍和分析了缓存击穿和雪崩的场景和解决案例,本文主要介绍缓存穿透。
缓存击穿,缓存穿透两个名词很像,很多人分不清。
- 击"穿": 数据在数据库中真是存在,缓存丢失,大量请求击穿数据库
- 穿"透": 数据在缓存中不存在,在数据库中也没有,就像透过数据库找数据一样
其实,击穿大部分情况是热点key丢失导致数据库宕机,而穿透绝大部分情况下是黑客脏数据重复请求,缓存和数据库中都不存在的数据频繁的查询,最后导致数据库宕机。
当然解决缓存穿透网上解决方案也是一大堆,有的说记录key,下次来就弹出去。有的说用大Map记录,每次进来get(key),如果存在就返回,布隆过滤器等等等,下面就分析一下这几个方案是否真的可行。
二、解决方案及分析
- Redis记录脏数据的key,请求进来Redis中进行脏数据对比
首先,当脏数据第一次进来的时候,缓存中脏数据是没有默认值的,所以肯定会打到数据库,这时候在缓存中给脏数据放一个默认值,这样当脏数据再进来的时候,缓存中有默认值,数据也能够成功返回。
这样的逻辑看似没什么问题,但是我们要考虑的问题是,请求脏数据是黑客发送的试探请求,并不是我们发的一个两个那么简单,是成百,上千甚至上万个请求,脏数据也是成百上千个。难道给这些脏数据全部设置上默认值放入缓存中?Redis的基于内存就那么多,难道要内存全部堆满脏数据?别的服务和组件的内存怎么办?所以,当请求足够多,脏数据也足够多的时候,拿Redis硬顶肯定是不行的。
- 服务中记录一个BigMap,用来记录脏数据
项目初始化的时候,初始一个全局的大Map,里面可以存放默认一批的数据,之后当脏数据请求过来以后,存放在大Map中,之后的每一次请求都会跟大Map中的数据做对比。这样的话,看似也没什么问题,Map,Hash存储Key,保证唯一。但是还是那个原因,数据量大了怎么办?大Map随着服务部署以后慢慢慢的扩大,请求延迟越来越高,返回效率越来越慢。而且微服务情况,难道我们每个服务都维护一个这样的Map么?是不是也不是很合理。
- 布隆过滤器
其实布隆过滤器,跟第二个大Map思想差不多,也是存储然后对比。这时候有人可能会问,同样的问题,数据量大了以后布隆过滤器不也会越来越大么?不都一样。
这就跟布隆过滤器的数据结构和实现原理有关,跟BigMap比起来效率要高得多。但是有个缺点就是不能删除,也就是当脏数据放进去以后,就删除不掉,这方面布谷鸟过滤器完美的解决了这个问题。
三、总结
第三部分布隆过滤器和布谷鸟过滤器,这两点我想作为单独的博客进行具体的分析,所以在这里只是给出方案,没有过多的解释,后续的博客中会出详细的解释。
本章完结,缓存击穿,雪崩,穿透大致就完结了。其实这三部分也只是简单的分析,跟实际业务中相差可能也很多,毕竟我也是个小菜鸟,对于大佬的思想差的还不是一星半点。但是在后续的博客中我还会完善,比如Redis集群下的分布式锁和穿透分析,等等。
分析了这么多方案,我想总结的是并不是哪个方案好,哪个方案不好,我只是想结合实际具体的分析下优缺点,不想说为了应付面试而背答案,这样其实是没什么意思的。