Redis高级篇(bitmap布隆过滤器)

目录

1、布隆过滤器是什么      

2、布隆过滤器特点

3、布隆过滤器的使用场景

4、代码实战,知行合一


1、布隆过滤器是什么      

        布隆过滤器(Bloom Filter)是一种空间效率高、处理速度快的概率型数据结构,用于判断一个元素是否存在于一个集合中。

        布隆过滤器由一个位数组(通常是一个大的二进制位数组)和一系列哈希函数组成。

2、布隆过滤器特点

        高效地插入和查询,减少内存占用,不保存数据信息,只存储一个标记位0、1。但返回的结果是不确定,有点小瑕疵。

        由于存在哈希冲突,一个元素判断结果(返回0或1)存在但元素不一定存在,判断结果不存在则一定不存在(有可能有,无肯定无)。

        可以保证的是,如果一个元素不在布隆过滤器中,则此元素一定不存在。

3、布隆过滤器的使用场景

1、解决缓存穿透问题,和Redis结合bitmap使用

2、黑名单校验、识别垃圾邮件 


二进制数组构建过程

  1. 预加载符合条件的记录
  2. 计算每条记录的哈希值
  3. 计算哈希值对应的bitmap数组位
  4. 修改值为1

查找元素的过程

  1. 计算元素的哈希值
  2. 计算哈希值对应的biamap数组位
  3. 找到数组中对应位置的值,0代表不存在,1代表存在

4、代码实战,知行合一

BloomFilterUtil 代码

package com.toonyoo.redis.bloomFilter.util;


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;


@Component
@Slf4j
public class BloomFilterUtil {

    public static final String CUSTOMER_REDIS_KEY = "customer:";

    // redis数据白名单key
    public static final String WHITE_LIST = "whiteList";

    @Autowired
    private StringRedisTemplate redisTemplate;


    /**
     * 布隆过滤器 初始化白名单数据
     */
    @PostConstruct
    public void init() {

        // 以当前数据库表中的一条数据为例
        String key = CUSTOMER_REDIS_KEY + "1266688003";

        // 1、通过key算哈希值
        int value = Math.abs(key.hashCode());
        // 2、通过哈希值与2^32取模,算bitmap对应的槽位
        long bitmap = (long) (value % Math.pow(2, 32));
        // 3、将key对应的槽位存入bitmap
        redisTemplate.opsForValue().setBit(WHITE_LIST,bitmap,true);
        log.info("布隆过滤器初始化白名单数据成功,{}对应的bitmap槽位:{}",key,bitmap);
    }

    /**
     *
     * @param keyItem 布隆过滤器的key即redis中bitmap存放的key == 白名单key
     * @param key   数据的key,即通过key算bitmap槽位
     * @return
     */
    public boolean checkBloomFilter(String keyItem, String key){

        // 1、通过key算哈希值
        int value = Math.abs(key.hashCode());
        // 2、通过哈希值与2^32取模,算bitmap对应的槽位
        long bitmap = (long) (value % Math.pow(2, 32));
        log.info("检查布Redis数据白名单,{}对应的bitmap槽位:{}",key,bitmap);
        // 3、查找key对应的槽位在bitmap中,bitmap中有则可能有,无则一定无
        return redisTemplate.opsForValue().getBit(keyItem, bitmap);
    }



}

业务层具体实现逻辑

package com.toonyoo.redis.bloomFilter;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.toonyoo.redis.bloomFilter.util.BloomFilterUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import static com.toonyoo.redis.bloomFilter.util.BloomFilterUtil.WHITE_LIST;

@Service
@Slf4j
public class CustomerService extends ServiceImpl<CustomerMapper, Customer> {


    @Autowired
    private CustomerMapper customerMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private BloomFilterUtil bloomFilterUtil;

    public static final String CUSTOMER_REDIS_KEY = "customer:";

    /**
     * 业务场景-模拟添加用户并回写进Redis
     *
     * @param customer
     */
    public void addCustomer(Customer customer) {

        if (customer != null) {
            // 向mysql中写入数据
            int i = customerMapper.insert(customer);
            // 若写入mysql成功
            if (i > 0) {
                // 缓存redis key
                String key = CUSTOMER_REDIS_KEY + customer.getId();
                // 将mysql中的数据重新掏出来
                Customer c = customerMapper.selectById(customer.getId());
                // 序列化
                String jsonString = JSON.toJSONString(c);
                // 回写进redis
                redisTemplate.opsForValue().set(key, jsonString);

                /**
                 * 此处不能将key存进布隆过滤器,因为存在缓存中的数据会过期,但bitmap不会过期。
                 * 若缓存大批量过期,先打到布隆过滤器,它认为是白名单,然后就会导致大批请求打到Redis而磁石Redis中数据已经过期
                 * 导致大量请求打到mysql。
                 */

            }
        }

    }

    /**
     * 模拟业务场景-读取redis数据
     * @param id
     */
    public Customer getCustomerById(Integer id) {

        Customer customer = null;
        // 缓存redis key
        String key = CUSTOMER_REDIS_KEY + id;

        // 最先查布隆过滤器是否存在此key,若无就直接return,这样可以防止缓存穿透
        boolean flag = bloomFilterUtil.checkBloomFilter(WHITE_LIST, key);

        // 无则一定无,拒绝访问,直接返回
        if (!flag){
            log.info("布隆过滤器中不存在此key,拒绝访问");
            return null;
        }

        // 先查redis
        String result = redisTemplate.opsForValue().get(key);
        // 反序列化
        customer = JSON.parseObject(result,Customer.class);
        // 若redis不在则去查mysql
        if (result == null){
            customer = customerMapper.selectById(id);
            // 若mysql存在数据,还需回写进redis
            if (customer != null){
                String jsonString = JSON.toJSONString(customer);
                redisTemplate.opsForValue().set(key,jsonString);
            }
        }
        return customer;
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redis提供的Bitmap可以作为布隆过滤器所需要的位数组的基础。布隆过滤器是一种数据结构,用于判断一个元素是否属于一个集合,具有高效的添加和查询操作。布隆过滤器使用一系列的哈希函数将元素映射到位数组中的多个位置,通过检查这些位置是否被置为1来判断元素是否存在。RedisBitmap就是一种位数组,可以将布隆过滤器的位数组存储在其中。Bitmap提供了位操作的功能,可以用来设置和查询位的状态。通过使用Bitmap,我们可以方便地实现布隆过滤器的添加和查询操作。因此,RedisBitmap正好适用于实现布隆过滤器的功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [借助Redis Bitmap实现简单的布隆过滤器](https://blog.csdn.net/huangchonghai/article/details/120340977)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [玩转Redis-Redis布隆过滤器的使用及原理](https://blog.csdn.net/u010887744/article/details/108700911)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值