关于redis:深入理解redis布隆过滤器BloomFilter

2次阅读

共计 2903 个字符,预计需要花费 8 分钟才能阅读完成。

1. 布隆过滤器是什么

2. 布隆过滤器的特点

3. 布隆过滤器应用场景

4. 布隆过滤器原理

5. 布隆过滤器优缺点

6. 布隆过滤器利用

7. 总结

1. 布隆过滤器是什么

redis 的布隆过滤器其实有点像咱们之前学习过的 hyperloglog 深刻了解 redis——新类型 bitmap/hyperloglgo/GEO,它也是不保留元素的一个汇合,它也 不保留元素的具体内容 ,然而 能断定这个元素是否在这个汇合中存在(hyperloglog 是断定汇合中存在的不反复元素的个数)。

1)它是由一个初值都为零的 bit 数组和多个哈希函数形成,用来疾速判断某个数据是否存在。

2)实质就是判断具体数据存不存在一个大的汇合中。

3)布隆过滤器是一种相似 set 的数据结构,只是统计 后果不太精确

2. 布隆过滤器的特点

1)一个元素如果在布隆过滤器里断定后果为 不存在,则肯定不存在
2)一个元素在布隆过滤器里断定结 果存在,则不肯定存在 (原理会在上面解释)
3)布隆过滤器 能够增加元素,然而不能删除元素 ,删除元素会导致 误判率减少。
4)误判只会产生在过滤器 没有增加过的元素 ,对于已 经增加过的元素 不会产生误判。

3. 布隆过滤器应用场景

1)解决缓存穿透的问题:

缓存穿透 是什么:
个别状况下,咱们在查问数据的时候,如果用到 redis,那么先去查 redis,如果 缓存中没有 ,再去查数据库,如果 数据库中也不存在 ,那么就产生了 缓存穿透

当产生缓存穿透的时候,可能会有 大量的查问直击 mysql,肯定水平上会拖垮数据库。

解决方案:
1.1)给空 key 设置一个空 value.
然而当 大量空 key进去的时候,也相当于查了很屡次 mysql,也可能会拖垮数据库。

1.2)应用布隆过滤器
把已存在的 key 保留在布隆过滤器中 ,相当于 redis 后面有一层布隆过滤器的爱护。
当呈现申请的时候:
1.2.1)先去查问布隆过滤器是否存在 (如果布隆过滤器返回为不存在,那是肯定不存在。)
1.2.2) 如果存在,才去 redis,甚至 mysql 查问,如果不存在,间接返回。

2)黑白名单的问题:
解决原理同上,把黑名单全副放入布隆过滤器,再进行过滤。

3)海量数据查找是否存在的问题都能够用布隆过滤器。(比方现有 50 亿个电话号码,和 10 万个电话号码,疾速精确地断定号码是否存在。)

4. 布隆过滤器原理

布隆过滤器应用了 多个 Hash 函数和一个初始值都为 0 的 bit 大型数组形成

add:
比方咱们当初有一个对象 obj1,它先用多个 hash 函数失去多个不同的值 再拿数组长度进行对这多个值取模失去多个地位 将这几个地位置为 1 ,就实现了 add 操作。

query:
查问的时候,只有多个哈希函数算进去的下标其中有一位是 0 就代表这个 key 不存在,如果都是 1,可能是存在,则可能遇上了哈希抵触(这就是为什么,布隆过滤器,无是肯定无,有可能有)。

为什么布隆过滤器不能删除:
如果布隆过滤器删除了一个元素,就是将某个对象的多个下标置为了 0,就大概率会影响到别的元素 因为很可能多个元素共享了某一个下标,所以删除元素会导致误判率减少。

5. 布隆过滤器优缺点

长处:高效地插入和查问,占用空间少

毛病:不能删除元素,存在误判。

6. 布隆过滤器利用

public class RedissonBloomFilterDemo {
    public static final int _1W = 10000;

    // 布隆过滤器里预计要插入多少数据
    public static int size = 100 * _1W;
    // 误判率, 它越小误判的个数也就越少
    public static double fpp = 0.03;
    
    static RedissonClient redissonClient = null;
    static RBloomFilter rBloomFilter = null;

    static {Config config = new Config();
        config.useSingleServer().setAddress("redis://192.168.111.147:6379").setDatabase(0);
        // 结构 redisson
        redissonClient = Redisson.create(config);
        // 通过 redisson 结构 rBloomFilter
        rBloomFilter = redissonClient.getBloomFilter("phoneListBloomFilter", new StringCodec());
        // 初始化布隆过滤器
        rBloomFilter.tryInit(size, fpp);

        // 1 测试  布隆过滤器有 +redis 有
        rBloomFilter.add("10086");
        redissonClient.getBucket("10086", new StringCodec()).set("chinamobile10086");

        // 2 测试  布隆过滤器有 +redis 无
        //rBloomFilter.add("10087");

        //3 测试,都没有

    }

    public static void main(String[] args) {String phoneListById = getPhoneListById("10087");
        System.out.println("------ 查问进去的后果:" + phoneListById);
        // 暂停几秒钟线程
        try {TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {e.printStackTrace();
        }
        redissonClient.shutdown();}

    private static String getPhoneListById(String IDNumber) {
        String result = null;

        if (IDNumber == null) {return null;}
            //1 先去布隆过滤器外面查问
        if (rBloomFilter.contains(IDNumber)) {
            //2 布隆过滤器里有,再去 redis 外面查问
            RBucket rBucket = redissonClient.getBucket(IDNumber, new StringCodec());
            result = rBucket.get();
            if (result != null) {return "i come from redis:" + result;} else {result = getPhoneListByMySQL(IDNumber);
                if (result == null) {return null;}
                // 从新将数据更新回 redis
                redissonClient.getBucket(IDNumber, new StringCodec()).set(result);
            }
            return "i come from mysql:" + result;
        }
        return result;
    }

    private static String getPhoneListByMySQL(String IDNumber) {return "chinamobile" + IDNumber;}
}

7. 总结

明天学习和总结了布隆过滤器,它是一种不保留数据,然而能断定数据是否在汇合中存在的一种数据类型。

正文完
 0