美文网首页编程语言
一次分清缓存穿透,缓存击穿,缓存雪崩

一次分清缓存穿透,缓存击穿,缓存雪崩

作者: 小马过河R | 来源:发表于2020-07-19 12:03 被阅读0次

    如果数据库查询压力过大怎么办?当然是上缓存了。似乎缓存就是为了缓解数据库压力而生,那就这样完了吗?自然不是,可曾遇到过面试Redis的时候经常被问什么是缓存穿透,缓存击穿,这两者有什么区别?啊,真是头大,一字之差。今天小马就来一起探讨下这一块呀。

    Redis为什么快

    Redis采用的是基于内存的单线程模型的key/value数据库,由C语言编写,官方提供的数据是可以达到100000+的QPS(每秒内查询次数)。单线程为什么这么快?主要还是得益于基于内存,哈希数据结构和单线程上。以下引用一段总结来解释。

    1、完全基于内存,绝大部分请求是纯粹的内存操作,数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);

    2、数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;

    3、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;

    4、使用多路I/O复用模型,非阻塞IO。“多路”指的是多个网络连接,“复用”指的是复用同一个线程;

    5、使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;

    缓存穿透

    啊,查了一下百度百科,似乎没有相关的解释,那只能自己来了。缓存穿透就是如果请求带着id过来了,像查询id=-1的数据,于是缓存里自然没有该数据,因为数据库本来也就没有该数据。那这个就有趣了,如果不断大量恶意请求,那就是直接绕过缓存,一直在查数据库,给数据库造成极大的压力,这就是缓存穿透。

    有了问题自然就要想法子解决,提供参考如下:

    1、在逻辑代码处做一层请求校验,例如,id的请求范围校验。如果请求的参数不符合规矩那就直接拒绝请求了,连缓存都拒绝请求了更别说请求到数据库了;

    2、尽量坏数据也做缓存。比如恶意请求的参数缓存和数据库库都获取不到数据一次就直接缓存为坏数据一段时间(比如有一个缓存池key都为bad_id系列,id请求过来后先查询key=bad_id系列是否有数据,没有的话再请求key=id的缓存数据),这样就可以缓解恶意请求带来的压力;

    3、那如果不是恶意请求,比如正常id=1的请求,此时刚好缓存没数据,数据库也查不到数据时,也是建议缓存处理,如处理为key=>null。但这个缓存时间要根据实际业务情况设置,不宜过长,比如30秒,否则会影响正常情况的获取(比如缓存为null期间数据库已经有写入相关参数的数据了,此时就出问题了)。

    4、布隆过滤器。可以使用布隆过滤器解决缓存穿透的问题,把已存在数据的key存在布隆过滤器中。当有新的请求时,先到布隆过滤器中查询是否存在,如果不存在该条数据直接返回;如果存在该条数据再查询缓存查询数据库。这个等下详细讨论,通俗理解为,当布隆过滤器说,某种东西存在时,这种东西可能不存在;当布隆过滤器说,某种东西不存在时,那么这种东西一定不存在。比如布隆还用在了识别垃圾邮箱的功能上。

    缓存击穿

    缓存击穿就是当请求参数过来,缓存中的数据瞬间过期,此时并发量又大,全部请求直接同时转为去请求数据库,瞬间给数据库带来巨大压力。

    参考的解决方案自然也有:

    1、设置热点数据永远不过期。这个法子最为粗暴了。

    2、加互斥锁。就是同一时间只能有一个请求去查询DB更新缓存。然后其他请求再从缓存中取数据。代码实现就是,对缓存过期后去请求数据库的操作加互斥锁,其他获取不到锁的请求直接等待(sleep)数秒后再去重新请求获取数据的方法,自然就能从缓存取数据了,真是智慧。

    3、将同一热点数据均匀分布在不同的缓存节点中(比如将key哈希分散存储,如id_hash(openid),单独设置过期时间),这样即可分散热key对redis的压力也可避免同一时间过期后大量请求一起同时涌向数据库查询数据。

    缓存穿透和击穿的区别

    这两者的区别上面已经很清晰了,总结一下,穿透就缓存无数据数据库也无数据,击穿就是缓存无数据数据库有数据。穿透一般是攻击行为导致,击穿很可能就是缓存处理不当导致。透为无则通透,击为有则击之。无则通透,有则击之,哈哈,这是小马的口诀。

    缓存雪崩

    啊,刚理清击穿和穿透,又来一个雪崩,真是头大。引用别人的一段话来解释,小马觉得概括得很是精辟易懂。

    缓存雪崩是指缓存中数据大批量同时到过期时间(比如redis服务突然挂了后重启),而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库

    解决方案建议:

    1、设置热点数据永远不过期;

    2、缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生,就是将缓存过期时间设置错开;

    3、将热点数据均匀分布在不同的缓存节点中,这样即可防止热点压力,又可以防止缓存同一时间过期,导致雪崩。这点和击穿的预防方法异曲同工。

    关于缓存击穿,缓存穿透,缓存雪崩就到这里了。值得一提的是,布隆过滤器是个一种比较巧妙的概率型数据结构,它可以告诉你某种东西一定不存在或者可能存在,比较有趣,这点有时间要细细起个篇幅探讨下。谢谢品阅。

    原创文章,未经允许请勿转载。

    相关文章

      网友评论

        本文标题:一次分清缓存穿透,缓存击穿,缓存雪崩

        本文链接:https://www.haomeiwen.com/subject/unplkktx.html