(4)缓存穿透问题的解决方案

问题

缓存中没有这样的数据,数据库中也没有这样的数据。由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。

方案

(1)布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。

(2)空结果缓存,简单粗暴的方法(我们采用的就是这种),如果一个查询返回的数据为(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很,最长不超过五分钟

(3)使用互斥锁排队,业界比价普遍的一种做法,即根据key获取value值为空时,锁上,从数据库中load数据后再释放锁。若其它线程获取锁失败,则等待一段时间后重试。这里要注意,分布式环境中要使用分布式锁单机的话用普通的锁(synchronized、Lock)就够了。

如何发现:

   我们可以分别记录cache命中数, storage命中数,以及总调用量,如果发现空命中(cache,storage都没有命中)较多,可能就会在缓存穿透问题。

   注意:缓存本身的命中率(例如redis中的info提供了类似数字,只代表缓存本身)不代表storage和业务的命中率。

一、布隆过滤器(推荐)

bloomfilter就类似于一个hash set,用于快速判某个元素是否存在于集合中,其典型的应用场景就是快速判断一个key是否存在于某容器,不存在就直接返回。布隆过滤器的关键就在于hash算法和容器大小,下面先来简单的实现下看看效果,我这里用guava实现的布隆过滤器:

可以看到,100w个数据中只消耗了约0.2毫秒就匹配到了key,速度足够快。然后模拟了1w个不存在于布隆过滤器中的key,匹配错误率为318/10000,也就是说,出错率大概为3%,跟踪下BloomFilter的源码发现默认的容错率就是0.03:

我们可调用BloomFilter的这个方法显式的指定误判率:

private static BloomFilter bloomFilter = BloomFilter.create(Funnels.integerFunnel(), capacity,0.01);

我们断点跟踪下,误判率为0.02和默认的0.03时候的区别:

对比两个出错率可以发现,误判率为0.02时数组大小为8142363,0.03时为7298440,误判率降低了0.01,BloomFilter维护的数组大小也减少了843923,可见BloomFilter默认的误判率0.03是设计者权衡系统性能后得出的值。要注意的是,布隆过滤器不支持删除操作。用在这边解决缓存穿透问题就是:

三、使用互斥锁排队

需求:假设有10000个请求,想达到第一次请求从数据库中获取,其他9999个请求从redis中获取这种效果。

常规写法:

常规的这种写法单线程没有问题,但是考虑到并发的存在,就会出现缓存渗透的问题,也就是不能保证其他9999个请求都是从redis中取。

常规写法的改进,使用双重检测锁

https://blog.csdn.net/fanrenxiang/article/details/80542580

http://www.cnblogs.com/geekdc/p/9256515.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 刚接触确定为恋爱关系的两个人,也许那一刻是最幸福的,没有无休止的争吵,没有柴米油盐的顾虑,更没有一天甚至一周又或...
    墨缇娜阅读 3,118评论 0 3
  • 好像很多人都有初恋情节。对曾经的爱情,百般留恋。时光会冲去不好的记忆,留下甜蜜的过去另人回味。 爱情里的很多东...
    巴斯阅读 1,616评论 0 0
  • 昨晚ali太屌了 微信上,老田没头没脑来这么一句。我的第一反应是去看股价,果然屌,一夜之间涨了超过13%。 你买了...
    润着阅读 4,654评论 0 0
  • 目录 | 《我们从未陌生过》 上一章 |《我们在这里练拳击,好吗?》 下一章 |《只有经济独立,才能灵魂挺拔》 文...
    我逐光而居阅读 3,738评论 3 19

友情链接更多精彩内容