文/小码农谈IT
如果数据库查询压力过大怎么办?当然是上缓存了。似乎缓存就是为了缓解数据库压力而生,那就这样完了吗?自然不是,可曾遇到过面试Redis的时候经常被问什么是缓存穿透,缓存击穿,这两者有什么区别?啊,真是头大,一字之差。今天就来一起探讨下这一块呀。
缓存穿透
啊,查了一下百度百科,似乎没有相关的解释,那只能自己来了。缓存穿透就是如果请求带着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),单独设置过期时间),这样即可分散压力也可避免同一时间统一时间过期大量请求一起涌向数据库查询数据。
缓存穿透和击穿的区别
这两者的区别上面已经很清晰了,总结一下,穿透就缓存无数据数据库也无数据,击穿就是缓存无数据数据库有数据。穿透一般是攻击行为导致,击穿很可能就是缓存处理不当导致。透为通透全无,击为有则击之,哈哈,这是小马的口诀。
缓存雪崩
啊,刚理清击穿和穿透,又来一个雪崩,真是头大。引用别人的一段话来解释,小马觉得概括得很是精辟易懂。
缓存雪崩是指缓存中数据大批量同时到过期时间(比如redis服务突然挂了后重启),而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库
解决方案建议:
1、设置热点数据永远不过期;
2、缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生,就是将缓存过期时间设置错开;
3、将热点数据均匀分布在不同的缓存节点中,这样即可防止热点压力,又可以防止缓存同一时间过期,导致雪崩。这点和击穿的预防方法异曲同工。
关于缓存击穿,缓存穿透,缓存雪崩就到这里了。值得一提的是,布隆过滤器是个一种比较巧妙的概率型数据结构,它可以告诉你某种东西一定不存在或者可能存在,比较有趣,这点有时间要细细起个篇幅探讨下。谢谢品阅。
举报/反馈

小码农谈IT

36获赞 103粉丝
分享IT技术,化繁为简,愿天下没有难学的IT
关注
0
0
收藏
分享