怎样应对缓存穿透问题(如何解决缓存穿透)
导语:怎样应对缓存穿透?
1为什么需要缓存
如果没有缓存,那么所有业务请求会直接指向数据库,以MySQL为例的数据库基本都是基于磁盘的,而磁盘I/O开销大,面对大规模请求时,会降低系统性能。对一些热点数据,将其从数据库中抽离出来放进缓存,每次查询时先走缓存,缓存命中则直接返回结果,能提高效率。2缓存带来的问题
有三个经典问题:
缓存雪崩:指缓存大面积失效,导致大量查询落到了数据库上,使数据库挂掉。缓存击穿:缓存中热点key突然失效,原本走缓存的大量请求直接打向了数据库,就好像在缓存中击穿了一个洞。缓存穿透:用户一直请求缓存和数据库都不存在的数据,每次请求缓存不命中,数据库也不命中,就像缓存不存在一样,同时不断地请求也给数据库带来压力。3应对方案
这里主要介绍 缓存穿透 的解决方案,先看两幅原理图。
用户请求大致原理图:
用户发出请求后先查缓存,缓存命中则直接返回;
缓存不命中就查数据库,查到后将数据写入缓存并返回给用户。
用户请求缓存和数据库都没有的数据(即缓存穿透,如请求id=-1的数据):
此时缓存基本失去了作用。
常见的解决思路:
将用户请求的不存在的数据也放进缓存,并将值置为null,这样请求走缓存的时候发现结果为null,直接返回即可。
但是需要给缓存中的key设置一个合适的过期时间,否则数据库中有了这样的数据,就会出现 数据不一致 问题。
更好的解决思路:
使用 布隆过滤器(Bloom Filter) 。 它可用于快速判断数据是否存在于某个集合中,借助这个功能,我们可用它来应对缓存穿透。
回顾一下布隆过滤器的两条重要特性:
1. 布隆过滤器判定数据存在,那么它可能存在也可能不存在。
2. 布隆过滤器判定数据不存在,那么它一定不存在。
加上布隆过滤器之后:
用户请求数据,若Bloom Filter返回false,则直接过滤该请求或返回null;若 Bloom Filter 返回true,则查缓存,缓存命中则返回,不命中则查数据库。
Bloom Filter 就好像是加在缓存前的一道 屏障 ,过滤了几乎所有不符合要求的请求。虽然有一定的误判率,即可能有少数通过了 Blo om Filter 的请求在数据库和缓存中也还是不命中,但相比之下,整个系统性能已经大大提升,且 Blo om Filter 的默认误判率只有0.03.
顺带提一下缓存击穿和缓存雪崩的解决方案。
缓存击穿:
在被查询的数据上加互斥锁,一条请求线程拿到锁后其它线程只能等待。
缓存雪崩:
事前:尽量保证整个 redis 集群的高可用性,发现机器宕机尽快补上。选择合适的内存淘汰策略。
事中:本地ehcache缓存 + hystrix限流&降级,避免MySQL崩掉。
事后:利用 redis 持久化机制保存的数据尽快恢复缓存。
本文内容由小馨整理编辑!