记录一次布隆过滤器与redis相结合的结果

需要导入的pom文件

<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.9.0</version>
</dependency>
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.6.2</version>
</dependency>
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>27.1-jre</version>
</dependency>
import com.base.constants.ConfigProperty;
import com.google.common.base.Charsets;
import com.google.common.primitives.Longs;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Pipeline;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;import static com.google.common.hash.Funnels.stringFunnel;
import static com.google.common.hash.Hashing.murmur3_128;
/*** 已解决的问题* 1.使用redis进行持久化操作* 2.value值超过redis所支持的最大512M时所产生的问题* 3.可以对错误进行回滚* 3.静态方法所产生的线程安全问题(redis的pipeline会有原子性问题,但对目前的实际使用没有影响,在对相同的key进行多线程判重的时候会出现问题)* 4.静态方法所产生的参数不一致问题* 可解决的问题* 目前可以先这样进行使用,待达到速度瓶颈后,可以使用本地与redis交互,本地进行去重,开多线程对redis进行持久化* 目前的速度大约1ms 1.3次判重(测试服务器,正式推测为2次,网络消耗严重)* 本地判重可达到1ms 15w次判重(根据处理器性能变化,3.9GHz频率下可达38w)* @author kuroha*/
public class BloomFilter {/*** redis key和value不能超过512M* 256M对应的bit数*/private static final long MAX_BIT = 2147483648L;/*** 256M对应的bit位数*/private static final int BIT_NUM = 31;private static Map<String,ThreadLocal<ArrayList<Long>>> threadLocalMap;private static Map<String,Object> map;private static JedisPool jedisPool;/*** 初始化参数*/static {ConfigProperty configProperty = ConfigProperty.getInstance();// redis服务器地址String host = configProperty.getRedisHost();// redis服务端口int port = Integer.parseInt(configProperty.getRedisPort());// redis访问密码String password = configProperty.getRedisPassword();// redisPool最大空闲连接数int maxIdle = Integer.parseInt(configProperty.getRedisPoolMaxIdle());// redisPool最大连接数int maxTotal = Integer.parseInt(configProperty.getRedisPoolMaxActive());// redisPool获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1long maxWaitMillis = Long.parseLong(configProperty.getRedisPoolMaxWait());// redisPool最小空闲连接数, 默认0int minIdle = Integer.parseInt(configProperty.getRedisPoolMinIdle());// redisPool逐出连接的最小空闲时间 默认1800000毫秒(30分钟)int timeout = Integer.parseInt(configProperty.getRedisTimeout());JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();jedisPoolConfig.setMaxIdle(maxIdle);jedisPoolConfig.setMaxTotal(maxTotal);jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);jedisPoolConfig.setMinIdle(minIdle);jedisPool = new JedisPool(jedisPoolConfig,host,port,timeout,password);threadLocalMap = new ConcurrentHashMap<>(4);map = new ConcurrentHashMap<>(3);// 获取redis数据// 如果需要对其他地方添加布隆去重算法,重新生成以下内容,并将jedis,numBits,numHashFunctions放入map中,用key区分// 获取bloomFlter的参数// 预期插入数量long expectedInsertions = Long.parseLong(configProperty.getBfExpectedInsertions());// 容错率double fpp = Double.parseDouble(configProperty.getBfFpp());long numBits = optimalNumOfBits(expectedInsertions, fpp);int numHashFunctions = optimalNumOfHashFunctions(expectedInsertions, numBits);Jedis jedis = new Jedis(host,port,0);jedis.auth(password);map.put(Const.BF_KEY_RK_CONTEXT_SEARCH+"numBits",numBits);map.put(Const.BF_KEY_RK_CONTEXT_SEARCH+"numHashFunctions",numHashFunctions);// 存入不同的ThreadLocalThreadLocal<ArrayList<Long>> rkThreadLocal = new ThreadLocal<>();threadLocalMap.put(Const.BF_KEY_RK_CONTEXT_SEARCH,rkThreadLocal);}public static void set(String key,String value) {jedisPool.getResource().set(key,value);}public static String get(String key){return jedisPool.getResource().get(key);}/*** 判断value是否存在于集合*/public static boolean isExist(String key, String value) {long[] indexs = getIndexs(key, value);boolean result = false;Jedis jedis = jedisPool.getResource();try (Pipeline pipeline = jedis.pipelined()) {for (long index : indexs) {pipeline.getbit(getRedisKey(key, index), index % MAX_BIT);}List<Object> returnAll = pipeline.syncAndReturnAll();result = !returnAll.contains(false);}catch (Exception e) {e.printStackTrace();}jedis.close();return result;}/*** 回滚操作* @param key*/public static void putRollBack(String key) {ThreadLocal<ArrayList<Long>> threadLocal = threadLocalMap.get(key);ArrayList<Long> indexs = threadLocal.get();threadLocal.remove();Jedis jedis = jedisPool.getResource();try (Pipeline pipeline = jedis.pipelined()) {for (long index : indexs) {if (index == -1) {break;}pipeline.setbit(getRedisKey(key, index), index % MAX_BIT, false);}pipeline.sync();} catch (IOException e) {e.printStackTrace();}jedis.close();}/*** 成功删除线程内变量* @param key*/public static void putSuccess(String key){threadLocalMap.get(key).remove();}/*** 将value存入redis bitmap*/public static void put(String key, String value) {long[] indexs = getIndexs(key,value);ArrayList<Long> threadLocalList = threadLocalMap.get(key).get();if (threadLocalList == null) {threadLocalList = new ArrayList<>();}Jedis jedis = jedisPool.getResource();try (Pipeline pipeline = jedis.pipelined()) {for (long index : indexs) {pipeline.setbit(getRedisKey(key, index), index % MAX_BIT, true);}List<Object> returnAll = pipeline.syncAndReturnAll();for (int i = 0; i < returnAll.size(); i++) {if (!(boolean) returnAll.get(i)) {threadLocalList.add(indexs[i]);}}} catch (IOException e) {e.printStackTrace();}jedis.close();threadLocalMap.get(key).set(threadLocalList);}/*** 用于使用前导入数据,相同key只需要一次* @param key* @param list*/public static void puts(String key,List<String> list) {Jedis jedis = jedisPool.getResource();try (Pipeline pipeline = jedis.pipelined()) {for (String value : list) {long[] indexs = getIndexs(key, value);for (long index : indexs) {pipeline.setbit(getRedisKey(key, index), index % MAX_BIT, true);}}pipeline.sync();} catch (IOException e) {e.printStackTrace();}jedis.close();}/*** 根据key获取bitmap下标*/private static long[] getIndexs(String key,String value) {byte[] bytes = hash(value);long hash1 = lowerEight(bytes);long hash2 = upperEight(bytes);long combinedHash = hash1;int numHashFunctions = (int) map.get(key + "numHashFunctions");long numBits = (long) map.get(key + "numBits");long[] result = new long[numHashFunctions];for (int i = 0; i < numHashFunctions; i++) {combinedHash = (combinedHash & Long.MAX_VALUE) % numBits;result[i] = combinedHash;combinedHash += hash2;}return result;}/*** 计算hash函数个数,guava中的实现* @param n* @param m* @return*/private static int optimalNumOfHashFunctions(long n, long m) {return Math.max(1, (int) Math.round((double) m / n * Math.log(2)));}/*** 计算bit数组长度,guava中的实现* @param n* @param p* @return*/private static long optimalNumOfBits(long n, double p) {if (p == 0) {p = Double.MIN_VALUE;}double log2 = Math.log(2);double logP = Math.log(p);return (long)(-n * logP / log2 / log2);}/*** 获取一个hash值,,guava中的实现*/private static byte[] hash(String key) {return murmur3_128().hashObject(key, stringFunnel(Charsets.UTF_8)).asBytes();}/*** 取hash的前8位,,guava中的实现* @param bytes* @return*/private static long lowerEight(byte[] bytes) {return Longs.fromBytes(bytes[7], bytes[6], bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0]);}/*** 取hash的后8位,,guava中的实现* @param bytes* @return*/private static long upperEight(byte[] bytes) {return Longs.fromBytes(bytes[15], bytes[14], bytes[13], bytes[12], bytes[11], bytes[10], bytes[9], bytes[8]);}/*** 获取redis键* @param key* @param index* @return*/private static String getRedisKey(String key,long index) {return StringUtil.splicingString("bf-",key,":",(index >> BIT_NUM));}

布隆过滤器与redis结合相关推荐

  1. Google布隆过滤器与Redis布隆过滤器详解

    一.什么是布隆过滤器? 布隆过滤器可以用来判断一个元素是否在一个集合中.它的优势是只需要占用很小的内存空间以及有着高效的查询效率.对于布隆过滤器而言,它的本质是一个位数组:位数组就是数组的每个元素都只 ...

  2. 开发过程中redis的rehash,布隆过滤器,redis持久化一起解决

    redis的rehash,布隆过滤器,redis持久化一节课搞定 1. 面试中rehash问题分析? 2. 面试中如何解释布隆过滤器? 3. redis持久化有哪些,项目中如何选择? 视频讲解如下,点 ...

  3. 布隆过滤器避免redis缓存穿透

    缓存穿透及布隆过滤器 Redis的基于缓存,极大地提升了应用程序的性能和效率,特别是数据查询方面,但是也带来了一些问题,比如典型的 缓存穿透.缓存雪崩.缓存击穿. 本篇先讲缓存穿透及其解决办法. (1 ...

  4. redis布隆过滤器PHP,Redis 中的布隆过滤器

    什么是『布隆过滤器』 布隆过滤器是一个神奇的数据结构,可以用来判断一个元素是否在一个集合中.很常用的一个功能是用来去重.在爬虫中常见的一个需求:目标网站 URL 千千万,怎么判断某个 URL 爬虫是否 ...

  5. Redis 高级主题之布隆过滤器(BloomFilter)

    最近计划准备整理几篇关于Reids高级主题的博文,本文整理的是关于布隆过滤器在Redis中如何应用,先来一张思维导图浏览全文. 1. 认识BloomFilter 1.1 原理 布隆过滤器,英文叫Blo ...

  6. redis的HyperLogLog与布隆过滤器

    HyperLogLog与布隆过滤器都是针对大数据统计存储应用场景下的知名算法. HyperLogLog是在大数据量的情况下关于数据基数的空间复杂优化实现,而布隆过滤是在大数据量情况下关于检索一个元素是 ...

  7. 清空缓存的命令_布隆过滤器应用——解决Redis缓存穿透问题

    1. 布隆过滤器 简要介绍布隆过滤器的概念和特点,详细知识请参考几篇参考文献或其它文章. 1.1 概念 简单点说,布隆过滤器本质是一个位数组. 当一个元素加入过滤器时,使用多个hash函数对元素求值, ...

  8. 解决Redis缓存穿透之布隆过滤器详解

    文章目录 1. 什么是Bloom Filter(布隆过滤器) 1.1 布隆过滤器优点 1.2 布隆过滤器缺点 1.3 布隆过滤器使用场景 1.4 布隆过滤器检索过程 1.5 布隆过滤器的算法描述 2. ...

  9. 视频教程- 19年录制Redis实战教程 高可用秒杀分布式锁布隆过滤器实战 SpringBoot教程整合-Java

    19年录制Redis实战教程 高可用秒杀分布式锁布隆过滤器实战 SpringBoot教程整合 7年的开发架构经验,曾就职于国内一线互联网公司,开发工程师,现在是某创业公司技术负责人, 擅长语言有nod ...

最新文章

  1. 微信小程序(六) 文章详情静态页面detail
  2. Something haunts me in Python
  3. 欢迎使用CSDN-markdown编辑器111
  4. sikuli 搜索例子
  5. 转载:better-scroll的相关api
  6. 2015 HUAS Summer Training#2 G
  7. 在线Javascript加密混淆工具
  8. epoll边缘触发_epoll事件通知机制详解,水平触发和边沿触发的区别
  9. 【教程搬运】廖雪峰Git的使用教程(一)
  10. 总结一下2010--2011初看的书
  11. 职称英语计算机考试取消,职称英语考试取消了吗
  12. 干货 | 拆解一个 Elasticsearch Nested 类型复杂查询问题
  13. windowsPE制作工具
  14. 【MacOS】Hammerspoon-sugood多合一效率工具,新增状态栏显示系统信息(CPU/内存/硬盘/网速)-v0.1.7
  15. 港珠澳大桥介绍网站设计【期末大作业】源码
  16. 湖南大学计算机考试题,湖南大学计算机组成原理期中考试题库
  17. 计算机应用数学 教材,计算机应用数学(第2版)
  18. mysql成绩表_mysql--学生课程成绩表
  19. [JS] checkbox 选中/全选/反选/不选
  20. php.符号,特殊符号大全

热门文章

  1. 啊哈算法第四章 万能的搜索
  2. 服务器3D场景建模(一):PyOpenGL
  3. beats android 蓝牙连接电脑,Beats Solo3如何连接电脑 Beats Solo3连电脑方法【介绍】...
  4. 正态分布的检验——JB检验
  5. friendly发音_“friendly”的反义词是什么? friendly 用中文怎么读
  6. 关于运行DynaSLAM源码这档子事(OpenCV3.x版)
  7. 骨传导蓝牙耳机哪款好、最受欢迎的骨传导蓝牙耳机品牌推荐
  8. 大数据就业薪资:学完大数据后就业薪资如何
  9. c语言指针 ppt,嵌入式C语言存储器及指针.ppt
  10. SegmentFault 思否联合开源社共同推出中国开源先锋 30 人评选