搜索
首页 > Java > Java面试题 > 正文

什么是缓存穿透?怎么解决?

月夜之吻
发布: 2025-09-07 08:17:01
原创
316人浏览过
缓存穿透指查询不存在的数据导致请求直达存储层,解决方案包括缓存空对象和布隆过滤器:缓存空对象适用于空数据较少场景,布隆过滤器适合空数据较多场景,可结合使用。

什么是缓存穿透?怎么解决?

缓存穿透是指查询一个根本不存在的数据,缓存层和存储层都不会命中,导致每次请求都直接打到存储层。这会给存储层带来巨大的压力,甚至可能导致服务崩溃。简单来说,就是“查无此项”带来的麻烦。

解决缓存穿透,核心思路是避免请求直接打到存储层。

解决方案:

  1. 缓存空对象: 当存储层返回空结果时,仍然将这个空结果缓存起来,但设置一个较短的过期时间。下次再查询相同Key时,缓存层会直接返回空结果,避免继续访问存储层。这个方法简单直接,但要注意过期时间的设置,过长可能导致数据不一致,过短则效果不佳。

  2. 布隆过滤器: 在缓存层前面设置一个布隆过滤器,将所有可能存在的Key预先加载到布隆过滤器中。当收到一个查询请求时,先判断Key是否存在于布隆过滤器中。如果不存在,则直接返回,避免访问缓存层和存储层。布隆过滤器是一种概率型数据结构,存在一定的误判率(False Positive),但可以有效地过滤掉大部分不存在的Key。

  3. 接口校验: 在接口层面进行校验,例如对用户ID进行格式校验,过滤掉明显非法的请求。这个方法可以防止恶意攻击,但需要根据具体的业务场景进行设计。

如何选择缓存空对象和布隆过滤器?

选择哪种方案取决于具体的业务场景。

  • 缓存空对象: 适用于数据不存在的情况比较少,或者数据不存在的Key相对固定的场景。例如,用户ID是自增的,那么不存在的用户ID通常也比较集中。
  • 布隆过滤器: 适用于数据不存在的情况比较多,或者数据不存在的Key不固定的场景。例如,商品ID是随机生成的,那么不存在的商品ID也比较分散。

一般来说,如果对误判率要求不高,且数据不存在的情况比较多,布隆过滤器是更好的选择。如果对误判率要求很高,或者数据不存在的情况比较少,缓存空对象是更好的选择。当然,也可以将两种方案结合使用,例如先使用布隆过滤器过滤掉大部分不存在的Key,再使用缓存空对象处理少量误判的Key。

布隆过滤器如何配置?

布隆过滤器的关键在于选择合适的哈希函数个数 k 和位数组大小 m。这两个参数会影响布隆过滤器的误判率。

  • 哈希函数个数 k 增加 k 可以降低误判率,但会增加计算成本。
  • 位数组大小 m 增加 m 可以降低误判率,但会增加内存消耗。

一般来说,可以根据以下公式估算合适的 mk

craiyon
craiyon

在线 AI 图像生成器

craiyon31
查看详情 craiyon
  • k ≈ (m / n) * ln(2)
  • 误判率 ≈ (1 - e^(-kn/ m))^ k

其中,n 是预计要存储的Key的数量。

例如,假设要存储100万个Key,希望误判率低于1%,那么可以计算出 m ≈ 9585058,k ≈ 7。

在实际应用中,可以使用现成的布隆过滤器库,例如 Google Guava 的

BloomFilter
登录后复制
类。配置示例如下:

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;

public class BloomFilterExample {

    public static void main(String[] args) {
        int expectedInsertions = 1000000;
        double fpp = 0.01; // 期望的误判率

        BloomFilter<Integer> bloomFilter = BloomFilter.create(
                Funnels.integerFunnel(),
                expectedInsertions,
                fpp);

        // 添加元素
        for (int i = 0; i < expectedInsertions; i++) {
            bloomFilter.put(i);
        }

        // 测试元素是否存在
        System.out.println(bloomFilter.mightContain(1)); // true
        System.out.println(bloomFilter.mightContain(1000000)); // false,但也可能误判为true
    }
}
登录后复制

缓存空对象时,过期时间应该设置多久?

缓存空对象的过期时间需要根据具体的业务场景进行权衡。

  • 过期时间过短: 缓存穿透的问题仍然可能存在,因为缓存很快就会过期,下次请求仍然会打到存储层。
  • 过期时间过长: 可能导致数据不一致,因为存储层的数据可能已经更新,但缓存层仍然是旧的空结果。

一般来说,可以根据以下原则设置过期时间:

  • 数据更新频率: 如果数据更新频率比较高,那么过期时间应该设置得短一些。
  • 数据一致性要求: 如果对数据一致性要求比较高,那么过期时间也应该设置得短一些。
  • 缓存穿透风险: 如果缓存穿透的风险比较高,那么过期时间可以适当设置得长一些。

一个常用的方法是使用动态过期时间。例如,可以根据存储层的响应时间来动态调整过期时间。如果存储层的响应时间比较快,那么可以设置较短的过期时间;如果存储层的响应时间比较慢,那么可以设置较长的过期时间。

除了上述方法,还有其他解决缓存穿透的方案吗?

还有一种比较少见的方案是存储层拦截。在存储层(例如数据库)中,可以设置一个拦截器,当收到一个查询请求时,先判断Key是否存在。如果不存在,则直接返回空结果,避免执行实际的查询操作。

这种方案的优点是可以完全避免缓存穿透,但缺点是会增加存储层的负担,并且需要修改存储层的代码。因此,除非对性能要求非常高,否则不建议使用这种方案。

另外,一些云服务提供商也提供了内置的缓存穿透防护功能,例如阿里云的CDN和腾讯云的DDoS防护。这些功能通常基于布隆过滤器或其他类似的技术,可以有效地防止缓存穿透攻击。

以上就是什么是缓存穿透?怎么解决?的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号