首页 > 图灵资讯 > 技术篇>正文

Redis布隆过滤器的原理和应用场景,解决缓存穿透

2023-04-20 16:56:30

 

 

大家好,我是哪吒。

布隆过滤器BloomFilter是什么?

BlomFilter是布隆过滤器专门用来解决去重问题的高级数据结果。

本质是一个大型位数组和几个不同的无偏hash函数,这意味着分布均匀。它由一个初始值为零的bit数组和多个哈希函数组成,用来判断一个数据是否存在。它和Hyperloglog一样,不太准确,有一定的误判概率。

布隆过滤器BlomFilter能做什么?

Redis布隆过滤器的原理和应用场景,解决缓存穿透_布隆过滤器

高效插入和查询占用空间少,返回结果不确定。如果一个元素被判断为存在,它就不一定存在;当它不存在时,它就不存在。

由于不同字符串的hashcode可能相同,布隆过滤器bloomfilter根据hashcode判断,如果hashcode存在,其对应的字符串不一定是您想要的字符串;但是,当hashcode不存在时,您想要的字符串肯定不存在,精品~

布隆过滤器BlomFilter只能添加元素,不能删除元素。

这与上述hashcode判断原理相同。同一hashcode的字符串将存储在index中。删除时,删除index。此时,可以删除具有相同hashcode的不同字符串和细品~

三、布隆过滤器使用场景1、解决缓存穿透问题

一般情况下,先查询Redis缓存,如果Redis中没有Redis,再查询MySQL。当数据库中没有此数据时,每次查询都要访问数据库,即缓存穿透。

在Redis前添加一层布隆过滤器,请先在布隆过滤器中判断。如果布隆过滤器不存在,直接返回,不再询问Redis和MySQL。

在布隆过滤器中存在时,再访问Redis,再访问数据库。

缓存穿透问题的完美解决方案。

Redis布隆过滤器的原理和应用场景,解决缓存穿透_redis_02

2、黑名单

如果黑名单很大,数千万,储存空间很大,在布隆过滤器中实现黑名单功能是一个很好的选择。

3、网页爬虫去除URL,避免爬取相同的URL地址。4.操作布隆过滤器BloomFilter1、使用布隆过滤器(1)初始bitmapp

布隆过滤器 本质上 是由长度为 m 位向量或位列表(仅包括) 0 或 1 由位值列表组成,最初的所有值都设置为 0。

Redis布隆过滤器的原理和应用场景,解决缓存穿透_redis_03

(2)添加key

使用多个hash函数对key进行hash操作,获得整数索引值,对位数组长度进行取模操作,获得位置,每个hash函数都会获得不同的位置,将这些位置的值置为1,表示添加成功。

比如我们加一个字符串“哪吒编程”,多次hash字符串(key) → 取模运行→ 得到坑位。

Redis布隆过滤器的原理和应用场景,解决缓存穿透_布隆过滤器_04

2、删除key

只要其中一个是零,就意味着key不存在,但如果都是1,就不一定存在相应的key。

3、判断它是否存在

查询布隆过滤器中是否存在key时,首先查询这个key key 通过相同的多个 hash 操作函数,检查相应位置是否为 1,

只要一个位置为零,就意味着布隆过滤器中的这个 key 不存在;

如果所有这些位置都是这样的话 1.这意味着它很有可能存在;

因为这些位置 1 也许是因为别的 key 由存在引起的,即上述hash冲突

五、代码实例1、使用Redis作为缓存
public class StudentSerivce {    public static final String CACHE_KEY = "student:";    @Resource    private StudentMapper studentMapper;    @Resource    private RedisTemplate redisTemplate;    public void addstudent(Student student){        int i = studentMapper.insertStudent(student);        if(i > 0)        {            //去数据库,重新获取新数据,做缓存            student=studentMapper.selectByKey(student.getId());            ///缓存key            String key=CACHE_KEY+student.getId();            //成功插入mysql,然后从mysql查询。然后插入redis            redisTemplate.opsForValue().set(key,student);        }    }    public Student findstudentById(Integer studentId){        Student student = null;        String key=CACHE_KEY+studentId;        // 查询redis        student = (Student) redisTemplate.opsForValue().get(key);        // redis没有,查询mysql        if(student==null){            // 从mysql中发现studentt            student=studentMapper.selectByPrimaryKey(studentId);            // mysql有,没有redis            if (student != null) {                // 在redisssql中写入mysql的数据                redisTemplate.opsForValue().set(key,student);            }        }        return student;    }}
2、布隆过滤器
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;/** * 布隆过滤器 -> redis -> mysql * @autor 哪吒编程 * @date 2023-04-17 */@Servicepublic class StudentServiceImpl implements StudentService {    public static final String CACHE_KEY = "student:";    @Autowired    private StudentMapper studentMapper;    @Autowired    private RedisTemplate redisTemplate;    public void addstudent(student student){        int i = studentMapper.insertSelective(student);        if(i > 0) {            //去数据库,重新获取新数据,做缓存            student=studentMapper.selectByPrimaryKey(student.getId());            ///缓存key            String key=CACHE_KEY+student.getId();            ///成功插入mysql,然后从mysql查询,然后插入rediss            redisTemplate.opsForValue().set(key,student);        }    }    public student findstudentById(Integer studentId){        student student = null;        ////缓存key的名字        String key=CACHE_KEY+studentId;        // 查询redis        student = (student) redisTemplate.opsForValue().get(key);        ///redis没有,查询mysql        if(student==null) {            student=studentMapper.selectByPrimaryKey(studentId);            // mysql有,没有redis            if (student != null) {                // 将mysql获得的数据写入rediss                redisTemplate.opsForValue().set(key,student);            }        }        return student;    }    /**     * BloomFilter -> redis -> mysql     * 白名单:whites     */    public student findStudentByIdWithBloomFilter (Integer studentId) {        student student = null;        String key = CACHE_KEY + studentId;        ///布隆过滤器校准,没有绝对没有,有可能有        if(!checkWithBloomFilter("whites",key)) {            log.info(无此客户信息的白名单:{}key);            return null;        }        ///查询redis        student = (Student) redisTemplate.opsForValue().get(key);        ///redis没有,查询mysql        if (student == null) {            student = studentMapper.selectByPrimaryKey(studentId);            // mysql有,没有redis            if (student != null) {                // 将mysql获得的数据写入rediss                redisTemplate.opsForValue().set(key, student);            }        }        return student;    }    /**     * 检查布隆过滤器是否存在     */    public boolean checkWithBloomFilter(String checkItem,String key) {        int hashValue = Math.abs(key.hashCode());        long index = (long) (hashValue % Math.pow(2, 32));        return redisTemplate.opsForValue().getBit(checkItem, index);    }}
六、总结
  1. 是的,可能有;没有,肯定没有;
  2. 使用Z时,初始化值尽可能满足实际元素长度,避免扩容;
  3. 当实际元素数量超过初始长度时,应重建布隆过滤器,然后批量添加所有历史元素;
上一篇 CDGP|以数字化转型为主要抓手,推动工业互联网创新发展
下一篇 spring和quartz进行定时邮件发送 (转)

文章素材均来源于网络,如有侵权,请联系管理员删除。