redis高级篇2 springboot+redis+bloomfilter实现过滤案例

一 bloomfilter的作用

1.1 作用

Bloomfilter:默认是有0组成bit数组和hash函数构成的数据结构,用来判断在海量数据中是否存在某个元素。

应用案例:解决缓存穿透。Bloomfilter放在redis前面,如果查询bf中没有则直接返回,如果存在则查询redis,如果redis不存在,则查询mysql数据库。bf拦截一些不必要的请求。

1.2 案例

1.2.1 流程逻辑

1.构建过程

1)预加载符合条件的记录;2)计算每条记录的hash值;3)计算hash值对应bitmap数组的位置;4)修改值为1;

2.查询过程

1)计算元素的hash位置;2)计算hash值对应二进制数组的位置;3)找到数组中对应位置的值,0代表不存在;1代表存在。

1.2.2 setbit的构建过程

1.@postConstruct初始化白名单数据

2.计算元素的hash值

3.通过上一步的hash值算出对应的二进制数组的坑位,将对应坑位的值修改为数字;1表示存在。

1.2.3 查询是否存在

1.计算元素的hash值;2通过上一步的hash值计算出对应的二进制数组对应的坑位,返回对应坑位的值,0表示无;1表示存在。

二 工程搭建

2.1 工程结构

2.2 不使用bloomfilter过滤器的情况 

2.2.1 新增初始化数据

1.controller

2.service

 2.2.2 查询数据

1.controller

 2.service

 2.2.3 初始化数据库

1.数据库配置

2.数据库脚本

CREATE TABLE `t_customer` (
  `id` bigint(11) NOT NULL,
  `cname` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `phone` varchar(255) DEFAULT NULL,
  `sex` varchar(255) DEFAULT NULL,
  `birth` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 2.2.4 启动服务测试

1.页面访问新增数据

http://localhost:8083/customer/add

2.访问查询接口

访问存在的数据id=1

访问不存在的数据id=3

 控制台显示信息:

2023-07-31 18:44:11.850  INFO 4172 --- [nio-8083-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
刚开始redis不存在。。。。。。

 3.查看数据库接口

4.查看redis

 2.3 使用bloomfilter过滤器的情况 

2.3.1 逻辑架构

2.3.2 初始化白名单数据

这里将customer:12作为key,存储到redis数据库中。

@Component
@Slf4j
public class BloomFilterInit
{
    @Resource
    private RedisTemplate redisTemplate;

    @PostConstruct //初始化白名单数据
    public void initWhiteListData(){
        //1.白名单客户加载到布隆过滤器中
        String key="customer:12";
        //2.计算hashvalues,由于存储计算出来可能存在负数,我们取绝对值
        int hashValue=Math.abs(key.hashCode());
        //3.通过hashvalue和2的32次方后取余,获得对应的下标坑位
        long index=(long)(hashValue%Math.pow(2,32));
        log.info("key"+"对应的index:"+index);
        //4.设置redis里面的bitmap对应的白名单 whitelistcustomer的坑位,将改值设置为1;
        redisTemplate.opsForValue().setBit("whiteListCustomer",index,true);
    }
}

截图

 2.3.3 使用bloomfilter过滤判断

 public Customer findDataByBloomFilter(Integer id){
        //1.封装key
        String key=CACHA_KEY_CUSTOMER+id;
        //2.布隆过滤器check,无是绝对无,有是可能有
        //===============================================
        if(!checkUtils.checkWithBloomFilter("whiteListCustomer",key))
        {
            log.info("白名单无此顾客,不可以访问: "+key);
            return null;
        }
       //3.查询redis
        Customer customer=(Customer) redisTemplate.opsForValue().get(key);
        if(customer==null){
            System.out.println("redis不存在。。。。。。");
            //4.redis为空,查询mysql
            customer=customerDao.selectByPrimaryKey(id);
            if(customer!=null){
                System.out.println("redis不存在,查询mysql存在");
                //5.mysql中数据存在, 把mysq查询出来的数据回写redis,保持一致性
                redisTemplate.opsForValue().set(key,customer);
                System.out.println("redis不存在,查询mysql存在,回写redis最新数据....");
            }
        }
        return customer;

    }

checkutil工具类:

package com.ljf.redis.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @auther zzyy
 * @create 2022-12-27 14:56
 */
@Component
@Slf4j
public class CheckUtils
{
    @Resource
    private RedisTemplate redisTemplate;

    public boolean checkWithBloomFilter(String checkItem,String key)
    {
        int hashValue = Math.abs(key.hashCode());
        long index = (long)(hashValue % Math.pow(2,32));
        boolean existOK = redisTemplate.opsForValue().getBit(checkItem,index);
        log.info("--->key:"+key+" 对应坑位下标index: "+index+" 是否存在:"+existOK);

        return existOK;
    }
}

2.截图

  2.3.4 判断测试

1.访问customer:1 但是初始白名单放入的是customer:12; 不存在则一定过滤掉。

控制台:

2023-07-31 18:47:43.243  INFO 4172 --- [io-8083-exec-10] com.ljf.redis.util.CheckUtils            : --->key:customer:1 对应坑位下标index: 1581185131 是否存在:false
2023-07-31 18:47:43.243  INFO 4172 --- [io-8083-exec-10] c.l.r.service.impl.CustomerServiceImpl   : 白名单无此顾客,不可以访问: customer:1

2.修改初始化白名单,customer:12 改为customer:1

3.再次启动服务,再次访问

4.控制台信息

 2023-07-31 19:10:08.794  INFO 19236 --- [nio-8083-exec-2] com.ljf.redis.util.CheckUtils            : --->key:customer:1 对应坑位下标index: 1581185131 是否存在:true

5.redis中查看

127.0.0.1:6379> get whiteListCustomer
@
127.0.0.1:6379> 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Sure!以下是一个示例代码,展示了如何在Java Spring Boot中使用布隆过滤器和Redis来解决缓存穿透问题: 首先,你需要在pom.xml文件中添加相应的依赖: ```xml <dependencies> <!-- Spring Boot Starter Redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- Guava Bloom Filter --> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>30.1-jre</version> </dependency> </dependencies> ``` 接下来,创建一个布隆过滤器的工具类 BloomFilterUtil.java: ```java import com.google.common.hash.BloomFilter; import com.google.common.hash.Funnels; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; @Component public class BloomFilterUtil { @Autowired private RedisTemplate<String, Object> redisTemplate; private BloomFilter<String> bloomFilter; // 设置布隆过滤器的预计插入数据量和误判率 private static final int EXPECTED_INSERTIONS = 1000000; private static final double FPP = 0.001; @PostConstruct public void init() { // 创建布隆过滤器,并将其保存到RedisbloomFilter = BloomFilter.create(Funnels.stringFunnel(), EXPECTED_INSERTIONS, FPP); redisTemplate.opsForValue().set("bloomFilter", bloomFilter); } public boolean mightContain(String key) { // 从Redis中获取布隆过滤bloomFilter = (BloomFilter<String>) redisTemplate.opsForValue().get("bloomFilter"); // 使用布隆过滤器判断key是否可能存在 return bloomFilter.mightContain(key); } public void put(String key) { // 从Redis中获取布隆过滤bloomFilter = (BloomFilter<String>) redisTemplate.opsForValue().get("bloomFilter"); // 将key添加到布隆过滤器中 bloomFilter.put(key); // 将更新后的布隆过滤器保存到RedisredisTemplate.opsForValue().set("bloomFilter", bloomFilter); } } ``` 然后,在你需要使用布隆过滤器解决缓存穿透的地方,注入 BloomFilterUtil,并使用它来判断数据是否存在于缓存中: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @RestController public class CacheController { @Autowired private BloomFilterUtil bloomFilterUtil; @GetMapping("/data/{key}") public String getData(@PathVariable String key) { // 先使用布隆过滤器判断key是否可能存在于缓存中 if (bloomFilterUtil.mightContain(key)) { // 如果可能存在,再从缓存中获取数据 String data = redisTemplate.opsForValue().get(key); if (data != null) { return data; } } // 如果数据不在缓存中,进行其他操作(例如从数据库中查询数据) // ... return null; } } ``` 这样,当有大量的请求同时访问某个缓存时,在经过布隆过滤器的判断后,可以避免无效的缓存查询请求,减轻了数据库的负载压力。 请注意,以上代码只是示例,实际使用时需要根据具体的业务需求进行适当的修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值