如何在springboot项目中redis使用布隆过滤器防止缓存穿透
程序员文章站
2022-04-15 18:32:50
上一篇博客讲到了布隆过滤器在java中的应用,这一篇说如何在springboot项目中redis使用布隆过滤器防止缓存穿透。先引入依赖 org.springframework.boot spring-boot-starter-data-redis&...
上一篇博客讲到了布隆过滤器在java中的应用,这一篇说
如何在springboot项目中redis使用布隆过滤器防止缓存穿透。
先引入依赖
<!--使用Redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--借助guava的布隆过滤器-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
yml redis配置
spring:
redis:
database: 3
host: 127.0.0.1
port: 6379
password: 12345
jedis.pool.max-idle: 100
jedis.pool.max-wait: -1ms
jedis.pool.min-idle: 2
timeout: 2000ms
两个工具类
BloomFilterHelper
package com.whrfjd.rescenter.utis;
import com.google.common.base.Preconditions;
import com.google.common.hash.Funnel;
import com.google.common.hash.Hashing;
public class BloomFilterHelper<T> {
private int numHashFunctions;
private int bitSize;
private Funnel<T> funnel;
public BloomFilterHelper(Funnel<T> funnel, int expectedInsertions, double fpp) {
Preconditions.checkArgument(funnel != null, "funnel不能为空");
this.funnel = funnel;
// 计算bit数组长度
bitSize = optimalNumOfBits(expectedInsertions, fpp);
// 计算hash方法执行次数
numHashFunctions = optimalNumOfHashFunctions(expectedInsertions, bitSize);
}
public int[] murmurHashOffset(T value) {
int[] offset = new int[numHashFunctions];
long hash64 = Hashing.murmur3_128().hashObject(value, funnel).asLong();
int hash1 = (int) hash64;
int hash2 = (int) (hash64 >>> 32);
for (int i = 1; i <= numHashFunctions; i++) {
int nextHash = hash1 + i * hash2;
if (nextHash < 0) {
nextHash = ~nextHash;
}
offset[i - 1] = nextHash % bitSize;
}
return offset;
}
/**
* 计算bit数组长度
*/
private int optimalNumOfBits(long n, double p) {
if (p == 0) {
// 设定最小期望长度
p = Double.MIN_VALUE;
}
int sizeOfBitArray = (int) (-n * Math.log(p) / (Math.log(2) * Math.log(2)));
return sizeOfBitArray;
}
/**
* 计算hash方法执行次数
*/
private int optimalNumOfHashFunctions(long n, long m) {
int countOfHash = Math.max(1, (int) Math.round((double) m / n * Math.log(2)));
return countOfHash;
}
}
RedisBloomFilter
package com.whrfjd.rescenter.utis;
import com.google.common.base.Preconditions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
/**
* @Author : JCccc
* @CreateTime : 2020/4/23
* @Description :
**/
@Service
public class RedisBloomFilter {
@Autowired
private RedisTemplate redisTemplate;
/**
* 根据给定的布隆过滤器添加值
*/
public <T> void addByBloomFilter(BloomFilterHelper<T> bloomFilterHelper, String key, T value) {
Preconditions.checkArgument(bloomFilterHelper != null, "bloomFilterHelper不能为空");
int[] offset = bloomFilterHelper.murmurHashOffset(value);
for (int i : offset) {
System.out.println("key : " + key + " " + "value : " + i);
redisTemplate.opsForValue().setBit(key, i, true);
}
}
/**
* 根据给定的布隆过滤器判断值是否存在
*/
public <T> boolean includeByBloomFilter(BloomFilterHelper<T> bloomFilterHelper, String key, T value) {
Preconditions.checkArgument(bloomFilterHelper != null, "bloomFilterHelper不能为空");
int[] offset = bloomFilterHelper.murmurHashOffset(value);
for (int i : offset) {
System.out.println("key : " + key + " " + "value : " + i);
if (!redisTemplate.opsForValue().getBit(key, i)) {
return false;
}
}
return true;
}
}
配置完成现在可以测试了。
redis布隆过滤器数据添加
@GetMapping("/redis/bloomFilter")
@ApiOperation("redis布隆过滤器数据添加")
public ResponseResult redisBloomFilter(){
List<String> allResourceId = resCenterDao.getAllResourceId();
for (String id : allResourceId) {
//将所有的资源id放入到布隆过滤器中
redisBloomFilter.addByBloomFilter(bloomFilterHelper,"bloom",id);
}
return new ResponseResult(ResponseEnum.SUCCESS);
}
redis布隆过滤器资源测试
@GetMapping("/redis/bloomFilter/resourceId")
@ApiOperation("redis布隆过滤器资源测试")
public ResponseResult redisBloomFilterResourceId(@RequestParam("resourceId")String resourceId){
boolean mightContain = redisBloomFilter.includeByBloomFilter(bloomFilterHelper,"bloom",resourceId);
if (!mightContain){
return new QueryResult<>(ResCenterEnum.RESOURCE_EXSIT,"");
}
return new ResponseResult(ResponseEnum.SUCCESS);
}
完成!
本文地址:https://blog.csdn.net/weixin_43748936/article/details/110225696