mysql布隆过滤器源码_布隆过滤器的demo

/**

* 缓存击穿

* @author

*

*/

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = {"classpath:config/spring/spring-dao.xml",

"classpath:config/spring/spring-bean.xml",

"classpath:config/spring/spring-redis.xml"})

public class CacheBreakDownTest {

private static final Logger logger = LoggerFactory.getLogger(CacheBreakDownTest.class);

private static final int THREAD_NUM = 100;//线程数量

@Resource

private UserDao UserDao;

@Resource

private RedisTemplate redisTemplate;

private int count = 0;

//初始化一个计数器

private CountDownLatch countDownLatch = new CountDownLatch(THREAD_NUM);

private BloomFilter bf;

List allUsers;

@PostConstruct

public void init(){

//将数据从数据库导入到本地

allUsers = UserDao.getAllUser();

if(allUsers == null || allUsers.size()==0){

return;

}

//创建布隆过滤器(默认3%误差)

bf = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), allUsers.size());

//将数据存入布隆过滤器

for(UserDto userDto : allUsers){

bf.put(userDto.getUserName());

}

}

@Test

public void cacheBreakDownTest(){

for(int i=0;i

new Thread(new MyThread()).start();

//计数器减一

countDownLatch.countDown();

}

try {

Thread.currentThread().join();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

class MyThread implements Runnable{

@Override

public void run() {

try {

//所有子线程等待,当子线程全部创建完成再一起并发执行后面的代码

countDownLatch.await();

} catch (InterruptedException e) {

e.printStackTrace();

}

//随机产生一个字符串

String randomUser = UUID.randomUUID().toString();

//String randomUser = allUsers.get(new Random().nextInt(allUsers.size())).getUserName();

String key = "Key:"+randomUser;

//如果布隆过滤器中不存在这个用户直接返回,将流量挡掉

if(!bf.mightContain(randomUser)){

System.out.println("bloom filter don't has this user");

return;

}

//查询缓存,如果缓存中存在直接返回缓存数据

ValueOperations operation = (ValueOperations) redisTemplate.opsForValue();

synchronized (countDownLatch) {

Object cacheUser = operation.get(key);

if(cacheUser!=null){

System.out.println("return user from redis");

return;

}

//如果缓存不存在查询数据库

List user = UserDao.getUserByUserName(randomUser);

if(user == null || user.size() == 0){

return;

}

//将mysql数据库查询到的数据写入到redis中

System.out.println("write to redis");

operation.set("Key:"+user.get(0).getUserName(), user.get(0).getUserName());

}

}

}

}

demo2

@RunWith(SpringRunner.class)

@SpringBootTest

public class BloomFilterTest {

private BloomFilter bloomFilter;

private int size = 1000000;

@Before

public void init(){

//不设置第三个参数时,误判率默认为0.03

//bloomFilter = BloomFilter.create(Funnels.integerFunnel(), size);

//进行误判率的设置,自动计算需要几个hash函数。bit数组的长度与size和fpp参数有关

//过滤器内部会对size进行处理,保证size为2的n次幂。

bloomFilter = BloomFilter.create(Funnels.integerFunnel(), size, 0.01);

for(int i = 0; i < size; i++){

bloomFilter.put(i);

}

}

@Test

public void testBloomFilter(){

for(int i = 0; i < size; i++){

if(!bloomFilter.mightContain(i)){

//不会打印,因为不存在的情况不会出现误判

System.out.println("不存在的误判" + i);

}

}

List list = new ArrayList<>(1000);

for (int i = size + 10000; i < size + 20000; i++) {

if (bloomFilter.mightContain(i)) {

list.add(i);

}

}

//根据设置的误判率

System.out.println("存在的误判数量:" + list.size());

}

}

布隆过滤器有以下应用场景:

1、黑名单,比如邮件黑名单过滤器,判端邮件地址是否在黑名单中。

2、网络爬虫,判端url是否已经被爬取过。

3、首次访问,判端访问网站的IP是否是第一次访问。

4、缓存击穿,防止非法攻击,频繁发送无法命中缓存的请求,导致缓存击穿,最总引起缓存雪崩。

5、检查英文单词是否拼写正确。

6、K-V系统快速判断某个key是否存在,典型的例子有Hbase,Hbase的每个Region中都包含一个BloomFilter,用于在查询时快速判断某个key在该region中是否存在,如果不存在,直接返回,节省掉后续的查询。

扩展,如何让布隆过滤器支持删除。

进行计数删除,但是计数删除需要存储一个数值,而不是原先的 bit 位,会增大占用的内存大小。这样的话,增加一个值就是将对应索引槽上存储的值加一,删除则是减一,判断是否存在则是看值是否大于0。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值