缓存穿透了怎么办?

时间:2022-07-22
本文章向大家介绍缓存穿透了怎么办?,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

缓存穿透了怎么办?

对应缓存来说,命中率是它的生命线。

在缓存命中率低的情况下,大量查询请求会穿透缓存到数据库,因为数据库对于并发的承受能力有限,一旦数据库承受不了大量查询任务,就会导致查询变慢,导致大量的请求阻塞在数据库查询上,造成应用服务器的连接和线程资源被占满,最终导致系统崩溃。

什么是缓存穿透

缓存穿透,其实是指从缓存中没有找到数据,不得已查询数据库的情况。

少量的缓存穿透没问题,主要由如下几点原因:

  • 一方面,缓存系统在容量上有限,不可能所有的数据都存储在缓存中
  • 另外一方面,互联网系统遵守 8/2 法则,也叫 帕雷托法则,最重要的事情只占 20%, 数据库访问,经常访问 20% 的热点数据,还有 80% 不会被经常访问。

什么样的缓存穿透对象系统有害

少量的缓存穿透是不可避免的,但是大量的请求穿透请求到后端系统,会造成系统后端崩溃。

如何解决缓存穿透

假设有这样一种场景:通过userid 查询用户信息,缓存读写策略是先查缓存,后查数据库。如果数据并不存在,在缓存和数据库中都没查询到数据,因此不会回种数据,这样下次请求到来,还是会先查缓存后查数据库,这种场景下,请求就穿透到了数据库。

回种空值

最大的问题在于数据库中不存在用户的数据,这样无理查询多少次,数据库中用于都不会存在这个用户的数据,一直会出现缓存穿透,因此,可以当数据从数据库查询为空或者发生异常时,在缓存中回种一个空值,给空值设置一个较短的过期时间,让短时间内能够快速过期淘汰。

Object nullValue =  new Object();
try {
 Object valueFromDB= getFromDB(uid);//从数据库中查询数据
 if(valueFromDB = null){
     cache.set(uid, nullValue,10);//如果从数据库中查询到空值,就把空值写入
 } else {
   cache.set(uid, value FromDB, 1000);
}catch(Exception e){
  cache.set(uid, nullValue, 10);
}

回种空值虽然能够阻挡大量的穿透请求,但是如果有大量的空值缓存,也就会浪费存储空间,就浪费缓存的存储空间。甚至会剔除掉另外一些已经把缓存的用户信息反而会造成命中率下降。

布隆过滤器

布隆过滤器可以用来判断一个元素是否存在一个集合中,这个算法由 二进制和 Hash 算法组成,它的基本思路:

我们把集合中的每一个值提供的 Hash 算法算出对应的 Hash 值,然后对Hash 值对数组长度取模后得到需要计入数组的索引值,并将数组这个位置的值从0改成1,再判断一个元素是否存在这个集合中,只需要将这个元素按照相同的算法计算出索引值。如果这个位置为1,就认为这个元素在集合中,否则不在集合中。

布隆过滤器

新建的用户需要写入数据库中,还更新布隆过滤器数组相应位置的值,当查询一个用户是否存在时,可以先查询布隆过滤器是否存在,如果不存在就直接返回,不需要查询数据库,这样的话可以极大的减少缓存穿透。

布隆过滤器有什么问题呢?我们下期聊!