缓存穿透:在这种情况下,缓存服务器找不到指定key的有效缓存信息,同时下游的数据库也查询不到对应的数据,这就造成了业务系统的无效请求全部落在了数据库上,缓存服务器完全没有起到作用。
解决方案:
1)缓存空数据,查询返回的数据为空,仍把这个结果进行缓存
优点:简单
缺点:消耗内存,可能发生不一致问题
2)布隆过滤器
优点:内存占用较少,没有多余key
缺点:实现复杂,存在误判
布隆过滤器是一种数据结构,用于快速检索一个元素是否可能存在于一个集合(bit数组)中。
它的基本原理是利用多个哈希函数,将一个元素映射成多个位,然后将这些位设置成1。当查询一个元素时,如果这些位都被设置成1,则认为元素可能存在于集合中,否则肯定不存在。
所以,布隆过滤器可以准确判断一个元素是否肯定不存在,但是因为hash冲突的原因,所以它没办法判断一个元素是否一定存在。只能判断可能存在。
误判率:如果判断元素存在,可能存在误判。跟数组长度有关,数组长度越长,误判率越低,但是内存消耗增大。数组长度越小,误判率越高,内存消耗越低。一般保证误判率在5%以内可以没满足需要。
流程:
使用步骤:
Java中可以使用第三方库来实现布隆过滤器,常见的有Google Guava库和Apache Commons库以及Redis
Guava
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
public class BloomFilterExample {
public static void main(String[] args) {
// 创建布隆过滤器,预计插入100个元素,误判率为0.01
BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringsFunctor(), 10, 0.01);
// 插入元素
bloomFilter.put("Hollis");
bloomFilter.put("666");
bloomFilter.put("八股文");
// 判断元素是否存在
System.out.println(bloomFilter.mightContain("Hollis")); // true
System.out.println(bloomFilter.mightContain("王星星")); // false
}
}
Apache Commons
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.collections4.BloomFilter;
import org.apache.commons.collections4.functors.HashTransformer;
public class BloomFilterExample {
public static void main(String[] args) {
// 创建布隆过滤器,预测插入100个元素,误判率为0.01
BloomFilter<String> bloomFilter = new BloomFilter<>(HashFunctionIdentity.hashFunction(String::hashCode), 100, 0.01);
bloomFilter.put("Hollis");
bloomFilter.put("666");
bloomFilter.put("八股文");
// 判断元素是否存在
System.out.println(bloomFilter.mightContain("Hollis")); // true
System.out.println(bloomFilter.mightContain("王星星")); // falses
// 清除所有已知条目
for (String key : bloomFilter.keys()) {
bloomFilter.remove(key);
}
}
}
3) Redis中可以通过Bloom模块来使用,使用Redisson可以:
//创建 Config 对象,设置单个服务器地址
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379/");
//创建 RedissonClient 对象
RedissonClient redisson = Redisson.create(config);
//获取 RBloomFilter 对象
RBloomFilter<String> bloomFilter = redisson.getBlobStore("myfilter").getOrInit(new StringSerializer<>());
//初始化布隆过滤器,参数分别为容量(max elements)和误识别率(false positive rate)
bloomFilter.tryInit(100, 0.01);
bloomFilter.add("Hollis");
bloomFilter.add("666");
bloomFilter.add("八股文");
System.out.println(bloomFilter.contains("Hollis"));
System.out.println(bloomFilter.contains("王巨星"));
//关闭客户端
redisson.shutdown();
或者Jedis
Jedis jedis = new Jedis("localhost");
jedis.bfCreate("myfilter", 100, 0.01);
jedis.bfAdd("myfilter", "Hollis");
jedis.bfAdd("myfilter", "666");
jedis.bfAdd("myfilter", "八股文");
System.out.println(jedis.bfExists("myfilter", "Hollis"));
System.out.println(jedis.bfExists("myfilter", "王星星"));
jedis.close();