布隆过滤器介绍及实战应用(防止缓存穿透)

news2025/1/19 8:00:32

布隆过滤器介绍

布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。

Hash面临的问题就是冲突。假设Hash函数是良好的,如果我们的位阵列长度为m个点,那么如果我们想将冲突率降低到例如 1%, 这个散列表就只能容纳m / 100个元素。显然这就不叫空间效率了(Space-efficient)了。解决方法也简单,就是使用多个Hash,如果它们有一个说元素不在集合中,那肯定就不在;如果它们都说在,也有可能性是不存在的。

布隆过滤器的优点:

• 时间复杂度低,增加和查询元素的时间复杂为O(N),(N为哈希函数的个数,通常情况比较小)

• 保密性强,布隆过滤器不存储元素本身

• 存储空间小,如果允许存在一定的误判,布隆过滤器是非常节省空间的(相比其他数据结构如Set集合)

布隆过滤器的缺点:

• 有点一定的误判率,但是可以通过调整参数来降低

• 无法获取元素本身

• 很难删除元素

在我们项目中使用布隆过滤器主要是为了解决Redis缓存穿透问题

基本使用

引入依赖

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.17.6</version>
        </dependency>

初始化布隆过滤器

/**
 * 容器启动成功以后,连上数据库,查到所有商品id。在布隆里面进行占位
 */
@Slf4j
@Service
public class SkuIdBloomInitService {

    @Autowired
    SkuInfoService skuInfoService;

    @Autowired
    RedissonClient redissonClient;


    //TODO 布隆只能增,不能删除商品,如果真的数据库删除了商品,需要定期布隆重建。
    //【重建】:按钮触发
    /**
     * 项目一启动就运行
     */
    @PostConstruct  //当前组件对象创建成功以后执行
    public void initSkuBloom(){
        log.info("布隆初始化正在进行....");
        //1、查询出所有的skuId
        List<Long> skuIds  = skuInfoService.findAllSkuId();

        //2、把所有的id初始化到布隆过滤器中
        RBloomFilter<Object> filter =
                redissonClient.getBloomFilter(SysRedisConst.BLOOM_SKUID);

        //3、初始化布隆过滤器
        //long expectedInsertions, 期望插入的数据量
        //double falseProbability  误判率
        boolean exists = filter.isExists();
        if(!exists){
            //尝试初始化。如果布隆过滤器没有初始化过,就尝试初始化
            filter.tryInit(5000000,0.00001);
        }
        //4、把所有的商品添加到布隆中。 不害怕某个微服务把这个事情做失败
        for (Long skuId : skuIds) {
            filter.add(skuId);
        }
        log.info("布隆初始化完成....,总计添加了 {} 条数据",skuIds.size());
    }

详情业务(布隆过滤器使用)

    /**
     *
     * 切面点表达式怎么写?
     *  execution(* com.atguigu.gmall.item.**.*(..))
     * @param skuId
     * @return
     */
    public SkuDetailTo getSkuDetailWithCache(Long skuId) {
        String cacheKey = SysRedisConst.SKU_INFO_PREFIX +skuId;
        //1、先查缓存
        SkuDetailTo cacheData = cacheOpsService.getCacheData(cacheKey,SkuDetailTo.class);
        //2、判断
        if(cacheData == null){
            //3、缓存没有
            //4、先问布隆,是否有这个商品
            boolean contain = cacheOpsService.bloomContains(skuId);
            if(!contain){
                //5、布隆说没有,一定没有
                log.info("[{}]商品 - 布隆判定没有,检测到隐藏的攻击风险....",skuId);
                return null;
            }
            //6、布隆说有,有可能有,就需要回源查数据
            boolean lock = cacheOpsService.tryLock(skuId); //为当前商品加自己的分布式锁。100w的49号查询只会放进一个
            if(lock){
                //7、获取锁成功,查询远程
                log.info("[{}]商品 缓存未命中,布隆说有,准备回源.....",skuId);
                SkuDetailTo fromRpc = getSkuDetailFromRpc(skuId);
                //8、数据放缓存
                cacheOpsService.saveData(cacheKey,fromRpc);
                //9、解锁
                cacheOpsService.unlock(skuId);

            }
            //9、没获取到锁
            try {Thread.sleep(1000);
               return cacheOpsService.getCacheData(cacheKey,SkuDetailTo.class);
            } catch (InterruptedException e) {

            }
        }
        //4、缓存中有
        return cacheData;
    }

 布隆重建

    @Override
    public void rebuildBloom(String bloomName, BloomDataQueryService dataQueryService) {
        RBloomFilter<Object> oldbloomFilter = redissonClient.getBloomFilter(bloomName);

        //1、先准备一个新的布隆过滤器。所有东西都初始化好
        String newBloomName = bloomName + "_new";
        RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(newBloomName);
        //2、拿到所有商品id
//        List<Long> allSkuId = skuInfoService.findAllSkuId();
        List list = dataQueryService.queryData(); //动态决定
        //3、初始化新的布隆
        bloomFilter.tryInit(5000000,0.00001);

        for (Object skuId : list) {
            bloomFilter.add(skuId);
        }

        //4、新布隆准备就绪
        // ob  bb  nb

        //5、两个交换;nb 要变成 ob。 大数据量的删除会导致redis卡死
        //最极致的做法:lua。 自己尝试写一下这lua脚本
        oldbloomFilter.rename("bbbb_bloom"); //老布隆下线
        bloomFilter.rename(bloomName); //新布隆上线

        //6、删除老布隆,和中间交换层
        oldbloomFilter.deleteAsync();
        redissonClient.getBloomFilter("bbbb_bloom").deleteAsync();
    }

测试

    @Scheduled(cron = "0 0 3 ? * 3")
    public void rebuild(){
//        System.out.println("xxxxxx");
        bloomOpsService.rebuildBloom(SysRedisConst.BLOOM_SKUID,bloomDataQueryService);
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1416349.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

最全全国十七个数据入表和资产化案例深度解析

2024年1月1日起&#xff0c;财政部会计司发布的《企业数据资源相关会计处理暂行规定》正式施行&#xff0c;规定为数据资源的会计处理提供了明确的指导原则。这一里程碑事件也标志着我国在数据资产入表领域正式进入实际操作阶段&#xff0c;随后&#xff0c;数据资产入表在全国…

[BJDCTF 2020]Easy

运行之后是这个东西 我们直接IDA暴力打开 结果main函数啥也不是 &#xff08;看其他人的wp知道了照que函数&#xff09; 我也不知道咋找的&#xff0c;可能真要硬找吧 int ques() {int v0; // edxint result; // eaxint v2[50]; // [esp20h] [ebp-128h] BYREFint v3; // [e…

在vscode里面聊微信

### 1、源起 事情是这样的&#xff0c;某天下午&#xff0c;我在做项目的时候被人事叫去谈话&#xff0c;说些有的没得&#xff0c;但是我注意到她说我不要玩微信&#xff0c;“我好几次都看到你在和别人聊微信”之类的话&#xff0c;所以我打算在ide工具的命令行中聊微信&…

聊聊效能与敏捷的差异

这是鼎叔的第八十四篇原创文章。行业大牛和刚毕业的小白&#xff0c;都可以进来聊聊。 欢迎关注本专栏和微信公众号《敏捷测试转型》&#xff0c;星标收藏&#xff0c;大量原创思考文章陆续推出。 近期&#xff0c;TesterHome社区小道消息播客直播间邀请了鼎叔&#xff0c;与…

程序员的基本素养之——R语言起源、特点以及应用

R语言是一种功能强大的数据分析、统计建模、可视化、 免费、开源且跨平台的编程语言 作为用于数据统计的必备技能语言&#xff0c;博主目前正在对R语言进行基本的学习&#xff0c;这也是生物信息学领域进行统计分析的必备语言之一。下面跟我来一起看看吧&#xff01; R语言是一…

产品解读 | 新一代湖仓集存储,多模型统一架构,高效挖掘数据价值

星环科技TDH一直致力于给用户带来高性能、高可靠的一站式大数据基础平台&#xff0c;满足对海量数据的存储和复杂业务的处理需求。 同时在易用性方面持续深耕&#xff0c;降低用户开发和运维成本&#xff0c;让数据处理平民化&#xff0c;助力用户以更便捷、高效的方式去挖掘数…

【PyTorch】n卡驱动、CUDA Toolkit、cuDNN全解安装教程

文章目录 GPU、NVIDIA Graphics Drivers、CUDA、CUDA Toolkit和cuDNN的关系使用情形判断仅仅使用PyTorch使用torch的第三方子模块 安装NVIDIA Graphics Drivers&#xff08;可跳过&#xff09;前言Linux法一&#xff1a;图形化界面安装&#xff08;推荐&#xff09;法二&#x…

第十三章认识Ajax(四)

认识FormData对象 FormData对象用于创建一个表示HTML表单数据的键值对集合。 它可以用于发送AJAX请求或通过XMLHttpRequest发送表单数据。 以下是FormData对象的一些作用&#xff1a; 收集表单数据&#xff1a;通过将FormData对象与表单元素关联&#xff0c;可以方便地收集表…

【GitHub项目推荐--建一个 ChatGPT 机器人】【转载】

建一个 ChatGPT 机器人 bot-on-anything 它可以将 ChatGPT 等算法模型应用于各类平台。目前&#xff0c;它已经可以接入到个人微信、公众号、QQ、Telegram、Gmail邮箱、Slack 等待&#xff0c;并计划接入Web、企业微信、钉钉等。 通过使用该开源项目&#xff0c;开发者可以通…

一天吃透面试八股文

内容摘自我的学习网站&#xff1a;topjavaer.cn 分享50道Java并发高频面试题。 线程池 线程池&#xff1a;一个管理线程的池子。 为什么平时都是使用线程池创建线程&#xff0c;直接new一个线程不好吗&#xff1f; 嗯&#xff0c;手动创建线程有两个缺点 不受控风险频繁创…

机器学习之numpy库

机器学习之numpy库 numpy库概述numpy库历史numpy的核心numpy基础ndarray数组内存中的ndarray对象ndarray数组对象的特点ndarray数组对象的创建ndarray对象属性的基本操作数组的维度元素的类型数组元素的个数数组元素索引(下标) ndarray对象数组的自定义类型切片操作一维数组切片…

【LTSpice】导入第三方元件库 之 subckt文件类型

LTSpice想要导入第三方的元件库&#xff0c;网上教程非常多。这里记录一下一种不用include命令实现、以后可以直接在component里面添加的 subckt文件的导入。过程比较复杂。 本文只讲解subckt文件&#xff01;如果发现文件里有.SUBCKT这样的文字&#xff0c;说明可以用本文的方…

[UI5 常用控件] 03.Icon, Avatar,Image

文章目录 前言1. Icon2. Avatar2.1 displayShape2.2 initials2.3 backgroundColor2.4 Size2.5 fallbackIcon2.6 badgeIcon2.7 badgeValueState2.8 active 3. Image 前言 本章节记录常用控件Title,Link,Label。 其路径分别是&#xff1a; sap.m.Iconsap.m.Avatarsap.m.Image 1…

贪吃蛇项目(基于C语言和数据结构中的链表)

建立文件 首先先建立3个文件。 Snake.h 函数的声明 Snake.c 函数的定义 Test.c 贪吃蛇的测试 分析项目 我们分析这整个项目 建立节点 首先在我们实现游戏开始的部分之前&#xff0c;我们要先创建贪吃蛇的节点&#xff0c;再由此创建整个贪吃蛇所包含的一些信息&#…

【王道数据结构】【chapter2线性表】【P44t17~t20】【统考真题】

目录 2009年统考 2012年统考 2015年统考 2019年统考 2009年统考 #include <iostream>typedef struct node{int data;node* next; }node,*list;list Init() {list head(list) malloc(sizeof (node));head->next nullptr;head->data-1;return head; }list Buyne…

机器学习 | 如何使用 Seaborn 提升数据分析效率

Seaborn和Matplotlib都是Python可视化库&#xff0c;它们都可以用于创建各种类型的图表。但是&#xff0c;Seaborn 和Matplotlib在概念和设计上有一些不同。 Matplotlib虽然已经是比较优秀的绘图库了&#xff0c;但是它有个今人头疼的问题&#xff0c;那就是API使用过于复杂&am…

人工智能系列:机器的进化(下)

大家好&#xff0c;接着上文的图灵机&#xff0c;继续介绍机器的进化。 1. 第一台计算机 世界上第一台电子计算机是ENIAC&#xff08;埃尼阿克&#xff09;&#xff0c;这是课本上所写的。但计算机学界对于究竟哪台是第一台电子计算机其实存在着争议&#xff0c;除了 ENIAC 以…

[嵌入式软件][启蒙篇][仿真平台] STM32F103实现SPI控制OLED屏幕

上一篇&#xff1a; [嵌入式软件][启蒙篇][仿真平台] STM32F103实现LED、按键 [嵌入式软件][启蒙篇][仿真平台] STM32F103实现串口输出输入、ADC采集 [嵌入式软件][启蒙篇][仿真平台]STM32F103实现定时器 [嵌入式软件][启蒙篇][仿真平台] STM32F103实现IIC控制OLED屏幕 文章目…

【Vue2 + ElementUI】更改el-select的自带的下拉图标为倒三角,并设置相关文字颜色和大小

效果图 实现 <template><div class"search_resources"><div class"search-content"><el-select class"search-select" v-model"query.channel" placeholder"请选择" change"handleResource&q…

【贪吃蛇:C语言实现】

文章目录 前言1.了解Win32API相关知识1.1什么是Win32API1.2设置控制台的大小、名称1.3控制台上的光标1.4 GetStdHandle&#xff08;获得控制台信息&#xff09;1.5 SetConsoleCursorPosition&#xff08;设置光标位置&#xff09;1.6 GetConsoleCursorInfo&#xff08;获得光标…