高并发系统设计十三-缓存穿透的解决方案

缓存的使用三-缓存穿透了如何解决

在低缓存命中率的系统中,大量查询请求会穿透缓存到数据库,因为数据库对于并发的承受能力比较脆弱,导致查询变慢,大量请求阻塞在数据库查询上,造成应用服务器的连接和线程资源被占满,导致系统崩溃。

1、缓存穿透的解决方案

场景一

通过用户ID查询用户的信息,缓存策略采用 Cache Aside 策略,如果读取一个用户表中未注册的用户会发生什么情况,我们会先读缓存再穿透读数据库。由于用户不存在,所有缓存和数据库中都没有查询到数据,因此也就不会想缓存中回种数据。当再次请求这个用户数据的时候就会再次穿透到数据库。

解决方案:回种空值以及使用布隆过滤器

1.1、回种空值

场景一中出现的问题,数据库中并不存在用户的数据,就造成了无论查询多少次数据库中永远不会存在这个用户的数据,穿透就一直会存在。

当从数据库中查询到空值或者发生异常时,我们可以向缓存中回种一个空值,但是考虑到占用缓存的空间,所以可以给空值加一个比较短的过期时间。

1.2、使用布隆过滤器

布隆过滤器的算法,用来判断一个元素是否在一个集合中。这种算法由一个二进制数组和一个 Hash 算法组成。

思路:

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

还是以存储用户信息的表为例进行讲解。首先我们初始化一个很大的数组,比方说长度为 20 亿的数组,接下来我们选择一个 Hash 算法,然后我们将目前现有的所有用户的 ID 计算出 Hash 值并且映射到这个大数组中,映射位置的值设置为 1,其它值设置为 0。

新注册的用户除了需要写入到数据库中之外,它也需要依照同样的算法更新布隆过滤器的数组中相应位置的值。那么当我们需要查询某一个用户的信息时,先查询这个 ID 在布隆过滤器中是否存在,如果不存在就直接返回空值,而不需要继续查询数据库和缓存,这样就可以极大地减少异常查询带来的缓存穿透。

1、选择多个 Hash 函数计算多个 Hash 值,这样可以减少误判的几率;


2、布隆过滤器会消耗一定的内存空间,所以在使用时需要评估你的业务场景下需要多大的内存,存储的成本是否可以接受。

发布了57 篇原创文章 · 获赞 3 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/wmdkanh/article/details/105568912