没有人告诉您如何解决更复杂的缓存渗透?

您应该在Internet上读过太多文章,说如何解决缓存渗透问题?它只不过是Bloom过滤器,缓存空值之类的东西。

但是,还有一个更深入的问题,缓存空值是否有问题?如果缓存中有太多空值怎么办?如果您使用redis,是否会有太多的空值打击您的redis?如果您使用本地缓存,它会消耗您的内存吗?然后的问题是,它仍然会炸毁您的数据库。

谈到不久前的在线问题,我们的在线环境压力测试表明,QPS超过2W后,RT达到了数十秒。

经过调查,发现redis连接数不够,导致大量的连接超时。

经过考虑,我们最终决定放弃redis缓存解决方案,改用本地缓存,因为我们缓存了一些配置信息,这在几个月内不太可能被修改,并且redis配置的连接数为200,5。

分钟到期后,数据量实际上只有几千。

实际上,这是没有必要的。

本地缓存可以完全解决问题。

本地缓存是使用Guava的LoadingCache实现的。

但是,在进行修改之后,经过压力测试,发现所有接口都进入了数据库以进行查询。

首先,检查代码以查看是否是导致实际故障生效的错误。

后来发现缓存渗透确实发生了。

现有记录引起了渗透问题。

实际上,使用redis时始终存在此问题,但由于连接数问题尚未发现。

下一步是考虑如何解决问题?由于我们要缓存一些配置信息和仅几千个数据,因此我们最终考虑一种简单的解决方案。

直接检查数据库中的所有密钥并缓存它们。

在检查数据库之前,请根据密钥直接对其进行过滤。

如果不存在,请直接返回。

不要查询数据库。

当然,这是因为我们的场景相对简单,因此可以直接对其进行处理。

那么,如果它更复杂,例如,亿万个缓存的数据呢?解决方案预过滤如果说像我的这样一些更简单的缓存,则可以使用我上面提到的解决方案。

还有一些缓存的密钥,例如ID,也可以根据某些作用域规则预先过滤。

例如,在明确知道缓存的密钥在10,000到100,000的范围内之后,就足以过滤掉此范围之外的请求并直接返回。

当然,很明显,此简单规则过滤适用于数据量不是很大且数据不经常更改的情况。

布隆过滤器对于上述情况,由于数据量很小,因此可以缓存简单的代码。

如果数据量很大(例如1亿个密钥),则使用Bloom过滤器是更好的解决方案。

我们可以每天从数据库中查询所有配置信息以构建位图。

在上一篇文章中,我还写了有关Bloom过滤器的文章,并张贴了上一张图片。

如果查询位置为1,则表示该键存在,否则,只要存在0,就表示该键绝对不存在。

使用布隆过滤器的缺点也很明显,并且存在一定的错误判断可能性。

当然,由于使用了它,因此应事先评估错误判断的比率,内存使用率和其他问题。

缓存空值是Internet上的一个坏问题,但是用于缓存空值的太多空值显然是有问题的。

另一个解决方案是迅速过期。

一般来讲,通用缓存的写法如下,先检查缓存,如果该缓存存在,则直接返回,如果该缓存不存在,则去数据库查询,结果不为空并将其保存在缓存中。

改进的版本用于缓存空对象,并且对于空数据,设置一个到期时间(例如10分钟)以快速到期,以防止出现太多的空值问题。

但是这种解决方案仍然存在一个小问题,即短期数据不一致的问题。

想象一下,如果此时缓存的null值实际上具有一个值,则在有效期内可能存在短暂的数据不一致。

缓存渗透的问题可以概括为三点。

这三种方法不是孤立的解决方案,它们可以一起使用。

首先看一下数据量。

如果数据量很小并且不经常更改,则可以选择预过滤方法并根据特定的业务规则进行处理。

如果数据量很大,则可以选择使用布隆过滤器,但存在一定的错误判断可能性。

通过预截取,大部分流量应为

欢迎您的咨询