SpringBoot使用布隆过滤器解决缓存穿透问题

 更新时间:2023年10月10日 08:38:09   作者:YIRC99  
缓存穿透是指当缓存系统中无法命中需要的数据时,会直接请求底层存储系统(如数据库),但是如果请求的数据根本不存在,那么大量的请求就会直接穿透缓存层,本文将给大家介绍一下SpringBoot使用布隆过滤器解决缓存穿透问题,需要的朋友可以参考下

缓存穿透基础介绍

缓存穿透是指当缓存系统中无法命中需要的数据时,会直接请求底层存储系统(如数据库),但是如果请求的数据根本不存在,那么大量的请求就会直接穿透缓存层,直接访问底层存储系统,导致底层系统压力过大,甚至崩溃。这也是缓存系统面临的一种常见攻击。

说白了就是查询大量不传在的key  绕过缓存 直接查询数据库 导致缓存跟不不存在一样 这就是缓存穿透

场景介绍

下面说下我的场景 我需要添加一个user 然后我再通过id去查询  如果查询有结果那就放入缓存 如果没有那就直接查询数据库 ?

这是添加user的方法

这是查询user的方法

问题描述

在这两个方法中 我虽然加入的缓存的机制 但是在查询user的方法中 会有一个问题 就是如果我查询的id是不存在的 那就会一直查询数据库

@Cacheable(value = "userCache", key = "#id", condition = "#result != null")

当然你可以说 我去掉注解上面的condition = "#result != null"   (这句话意思是condition 条件为真才缓存)  这样就算我查询一个不存在的id 然后将一个null或者空对象返回 然后再加入缓存不就可以啦  下次再去查询这个不存在的id的时候 就不会走数据库了  

可是 如果我每一次查询的都是不同的并且不存在的id呢? 那么这个问题还是无法解决 那么接下来就可以引入布隆过滤器  布隆过滤器具体的原理我这里就不做解释了

解决问题

第一步在maven中导入布隆过滤器  事先说明 导入的方法很多 我的方法不一定是最优的 但是一定是能行的

在pom.xml中引入依赖

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>30.1-jre</version>
        </dependency>
        Guava库(Google Guava)是一个Google开发的Java工具库,
        它提供了许多常用的Java工具类和数据结构,包括布隆过滤器(Bloom Filter)

创建项目结构 这个不需要解释吧 能看这种文章的 我相信项目结构应该都是能看懂的?

AppConfig的代码如下 就是简单的注入Bean对象

@Configuration
public class AppConfig {
    @Bean
    public BloomFilterService bloomFilterService() {
        return new BloomFilterService();
    }
}

BloomFilterService的代码如下

public class BloomFilterService {
    private BloomFilter<Long> bloomFilter;
    public BloomFilterService(){
        // 创建一个布隆过滤器,设置期望插入的元素数量和误判率
        int  bloomFilterSize = 1000;  // 期望插入的元素数量
        double falsePositiveRate = 0.001; // 误判率
        bloomFilter = BloomFilter.create(Funnels.longFunnel(), bloomFilterSize, falsePositiveRate);
    }
    // 添加元素到布隆过滤器
    public void add(Long id){
        bloomFilter.put(id);
    }
    //判断元数是否在布隆过滤器中
    public boolean contains(Long id){
        return bloomFilter.mightContain(id);
    }
}

接下来就是在controller中引入并且使用布隆过滤器了

正常注入

    @Autowired
    private BloomFilterService bloomFilterService;

然后在每一次添加对象之后都将用户的id添加到布隆过滤器中

    @CachePut(value = "userCache", key = "#user.id") // value 指定缓存的名字
    @PostMapping
    public User save(User user){
        userService.save(user);
        bloomFilterService.add(user.getId()); 
        //这里注意必须要放在添加之后 因为一开始传过来的user是没有id的 会有空指针错误
        //这里利用的查询回显 不懂的可以去查查
        return user;
    }

然后更改查询方法 这样每一次查询user的时候都会先过一遍布隆过滤器 然后再去查询用户 如果存在那么就加入缓存 不传在就会被布隆过滤器拦截 注意去掉, condition = "#result != null" 这个好像跟 布隆有冲突 如果有懂的可以在评论区提一下

    @Cacheable(value = "userCache", key = "#id")
    @GetMapping("/{id}")
    public User getById(@PathVariable Long id){
        if (!bloomFilterService.contains(id)) {
            // ID 不合法,可以返回错误响应或进行其他处理
            return null;
        }
        User byId = userService.getById(id);
        return byId;
    }

最后的效果

在添加的时候会将id添加到布隆中 下一次查询的时候如果添加的数据不合法 那就直接拦截

如果添加的数据是合法的 那么就会直接查缓存  如果缓存没有那就直接查数据库 然后再加入缓存

上面的效果我自己测试了发现是没有什么问题的 本人的水平也不高 如果有发现什么问题欢迎评论区讨论 谢谢观看

以上就是SpringBoot使用布隆过滤器解决缓存穿透问题的详细内容,更多关于SpringBoot缓存穿透的资料请关注脚本之家其它相关文章!

相关文章

  • 基于Java并发容器ConcurrentHashMap#put方法解析

    基于Java并发容器ConcurrentHashMap#put方法解析

    下面小编就为大家带来一篇基于Java并发容器ConcurrentHashMap#put方法解析。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • java 基本算法之归并排序实例代码

    java 基本算法之归并排序实例代码

    这篇文章主要介绍了java 基本算法之归并排序实例代码的相关资料,需要的朋友可以参考下
    2017-05-05
  • 关于mybatis-plus插件使用时的一些问题小结

    关于mybatis-plus插件使用时的一些问题小结

    这篇文章主要给大家介绍了关于mybatis-plus插件使用时的一些问题的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-03-03
  • 教你如何用Java替换Word中带有${}的内容

    教你如何用Java替换Word中带有${}的内容

    这篇文章主要介绍了教你如何用Java替换Word中带有${}的内容,文中有非常详细的代码示例,对正在学习java的小伙伴们有很好的帮助,需要的朋友可以参考下
    2021-04-04
  • SSH框架网上商城项目第9战之添加和更新商品类别功能实现

    SSH框架网上商城项目第9战之添加和更新商品类别功能实现

    这篇文章主要为大家详细介绍了SSH框架网上商城项目第9战之添加和更新商品类别功能实现,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • Java新特性之Optional类超详细介绍

    Java新特性之Optional类超详细介绍

    这篇文章主要给大家介绍了关于Java新特性之Optional类超详细介绍的相关资料,Java8中的Optional类是一个容器对象,可以包含null或非null值,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2023-07-07
  • Java 多线程死锁的产生以及如何避免死锁

    Java 多线程死锁的产生以及如何避免死锁

    这篇文章主要介绍了Java 多线程死锁的产生以及如何避免死锁,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • 基于Redis生成分布式全局唯一ID的3种策略

    基于Redis生成分布式全局唯一ID的3种策略

    在分布式系统设计中,全局唯一ID是一个基础而关键的组件,Redis具备高性能、原子操作及简单易用的特性,因此我们可以基于Redis实现全局唯一ID的生成,下面我们来看看实现的三种方法吧
    2025-04-04
  • Eclipse git推送上传错误问题解决方案

    Eclipse git推送上传错误问题解决方案

    这篇文章主要介绍了Eclipse git推送上传错误问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • Java实现顺序表的操作

    Java实现顺序表的操作

    这篇文章主要为大家详细介绍了Java实现顺序表的基本操作,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01

最新评论