常见的一台MySql服务器的并发量为600左右
redis数据类型:(9种) string、hash、list、set、zset、bitmap、hyperloglogs、geo、streams
爬虫判断url是否爬取过?url地址过滤方法
布隆过滤器BloomFilter
本质上布隆过滤器是一种数据结构,比较巧妙的概率型数据结构(probabilistic data structure),特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”。
如果布隆过滤器判断存在的,可能存在
如果布隆过滤器判断不存在的,一定不存在
使用多个hash函数的原因:减少hash冲突和hash碰撞引起的误判
简单使用方法
Google的guava包中提供了布隆过滤器的实现,下面给出一个简单使用测试:
引入Guava package
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>25.0-jre</version>
</dependency>
public class BloomfilterTest {
private static int size = 1000000; // 预计插入的数据
private static double fpp = 0.001; // 容错率
private static BloomFilter<Integer> bloomFilter =
BloomFilter.create(Funnels.integerFunnel(), size, fpp);
public static void main(String[] args) {
// 插入数据
for (int i = 0; i < 1000000; i++) {
bloomFilter.put(i);
}
// 模拟误判
int count = 0;
for (int i = 1000000; i < 2000000; i++) {
if (bloomFilter.mightContain(i)) {
count++;
System.out.println(i+"误判了!");
}
}
System.out.println("总误判数"+count);
}
}
其中BloomFilter中默认的容错率为0.03
// com/google/common/hash/BloomFilter.class
public static <T> BloomFilter<T> create(Funnel<? super T> funnel, long expectedInsertions) {
return create(funnel, expectedInsertions, 0.03D);
}
容错率设置的越低,总误判数就会越低,即匹配的精度就会越高,但占用的存储空间也会越大(如上图所示),因此在实际使用时需要权衡二者进行容错率的选取。
分布式场景如何解决
使用redis中的布隆过滤器:
加载布隆过滤器的相关插件,在redis配置文件中设置
BloomFilter的优点
在request和业务之间添加布隆过滤器进行非法访问拦截:
- 减少不必要的IO操作
- 减少无效访问
- 防止缓存穿透
布隆过滤器BloomFilter应用
在实际工作中,布隆过滤器常见的应用场景如下:
- 网页爬虫对 URL 去重,避免爬取相同的 URL 地址;
- 反垃圾邮件,从数十亿个垃圾邮件列表中判断某邮箱是否垃圾邮箱;
- Google Chrome 使用布隆过滤器识别恶意 URL;
- Medium 使用布隆过滤器避免推荐给用户已经读过的文章;
- Google BigTable,Apache HBbase 和 Apache Cassandra 使用布隆过滤器减少对不存在的行和列的查找。
解决缓存穿透问题
除了上述的应用场景之外,布隆过滤器还有一个应用场景就是解决缓存穿透的问题。
所谓的缓存穿透就是服务调用方每次都是查询不在缓存中的数据,这样每次服务调用都会到数据库中进行查询,如果这类请求比较多的话,就会导致数据库压力增大,这样缓存就失去了意义。
利用布隆过滤器我们可以预先把数据查询的主键,比如用户 ID 或文章 ID 缓存到过滤器中。当根据 ID 进行数据查询的时候,我们先判断该 ID 是否存在,若存在的话,则进行下一步处理。若不存在的话,直接返回,这样就不会触发后续的数据库查询。需要注意的是缓存穿透不能完全解决,我们只能将其控制在一个可以容忍的范围内。
参考资料:
https://juejin.cn/post/6844904007790673933