布隆过滤器之防止缓存击穿
为什么使用布隆过滤器
- 布隆过滤器可以用于检索一个元素是否在一个集合中的重要工具,具有快速,比哈希表更节省空间等优点,而缺点在于有一定的误识别率
- 布隆过滤器(bloom filter)是Google Guava类库里面的组件
- 当代换联网环境下使用缓存的公司可说遍地都是大家都知道使用缓存就是为了缓存一些冷数据以减少数据库压力
- 查询一些缓存不存在的数据 透过缓存直接查询数据库
![](https://i-blog.csdnimg.cn/blog_migrate/24d2f1f96c742cdaa2df6422a3091bf5.jpeg)
- 服务报错
![](https://i-blog.csdnimg.cn/blog_migrate/9048741c37d4e1a4b458bf3f4610f4be.jpeg)
布隆过滤器介绍
- bloom算法类似一个hash set,用来判断某个元素(key)是否在某个集合中和一般的hash set不同的是,这个算法无需存储key的值,对于每个key,只需要k个比特位,每个存储一个标志,用来判断key是否在集合中
- 初始化时会初始化一个长度为n比特的数组,每个比特位初始化为0(n值个数由误判率决定,误判率越小则n值越大,误判率越大则n值越小)
- 某个key加入集合时,用k个hash函数计算出k个散列值,并把数组中对应的比特位置为1
- 判断某个key是否在集合时,用k个hash函数计算出k个散列值,并查询数组中对应的比特位,如果所有的比特位都是1,认为在集合中(k值个数由误判率决定,误判率越小则k值越大,误判率越大则k值越小)
- 不需要存储key,节省空间
布隆过滤器代码实现
- 代码实现
package com.f.fmodules.fuser.bloom;
import com.google.common.base.Charsets;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import java.util.*;
public class BloomFilterDemo {
public static void main(String[] args) {
final int count = 500000;
List<String> stringList = new ArrayList<>(count);
Set<String> stringSet = new HashSet<>();
//创建布隆过滤器 初始化过滤器数据
BloomFilter<String> bloomString = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8),count);
for (int i =0;i< count;i++){
String id = UUID.randomUUID().toString();
stringList.add(id);
stringSet.add(id);
bloomString.put(id);
}
int wrong = 0;
int right = 0;
for (int i =0;i< count; i++) {
String checkString = i % 100 == 0 ? stringList.get(i) : UUID.randomUUID().toString();
//布隆过滤器 进过hash算法和byte数组 校验是否存在于集合中
if (bloomString.mightContain(checkString)){
//校验是否误判
if (stringSet.contains(checkString)){
right++;
}else{
wrong++;
}
}
}
System.out.println("50万测试数据-->共抵挡: "+(count - wrong - right)+"次非法入侵"+" 误判"+wrong);
}
}
- 运行结果
![](https://i-blog.csdnimg.cn/blog_migrate/aecabfab4b7ee628dcfd1517a136c2c7.jpeg)
- 成功访问5000是正确答案 50万对100取模 刚好是5000
为什么会有14721次误判呢 咱们跟进源码进行深入探索 ![](https://i-blog.csdnimg.cn/blog_migrate/be022b1d9c9520757640d62dcd5beb13.jpeg)
深入源码可发现 误判率在百分之三的情况下 有300多万个byte数组 会进行5次hash算法进行判断数据是否存在已知数据中 - 初始化布隆过滤器时设置误判率为0.01
//创建布隆过滤器 初始化过滤器数据
BloomFilter<String> bloomString = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8),count,0.001);
- debug深入源码
![](https://i-blog.csdnimg.cn/blog_migrate/6faaa0404cc724547cbd87a3c50a5057.jpeg)
此时发现误判率设置为百分之一的情况下 byte数组达到七百多万 而需要进行的hash算法次数达到十次 - 查看运行结果
![](https://i-blog.csdnimg.cn/blog_migrate/1ec223c3a65f5f5c141701bcd0a71e12.jpeg)
结果可看出 误判率为百分之一的情况下 5000次正确访问 只有500多次误判
思考
- 算法判断key在集合中时,有一定的概率key其实不在集合中
- 并不是设置的误判率越小越好,误判率越小代表需要进行hash计算次数越多消耗资源越多,应根据实际情况进行决策
- k值无法删除
总结
- 个人觉得若使用此过滤器(条件允许的情况下)可专门用一台服务区用来初始化集合里面的值.
转载于:https://my.oschina.net/u/3498817/blog/3038195