大家好,我是程序媛雪儿,今天想和大家聊聊redis缓存穿透。
一、什么是缓存穿透
缓存穿透:查询一个不存在的数据,mysql查询不到的数据也不会直接写入缓存,导致每次请求都查数据库。
正常流程如下:
但是如果查的数据不存在,便会一直访问数据库,造成缓存穿透。
二、解决方案
方案一:缓存空数据,就是把空数据也缓存到redis中
优点:简单
缺点:消耗内存。如果该id有了数据,从缓存里取到的还是空数据,会发生数据不一致问题
方案二:布隆过滤器
正常流程:
布隆过滤器算法如下:
简单说就是把数据id用hash计算3次,得到三个位数,如果有值就记为1。
那么通过布隆过滤器判断id是否有值,就是把用户传入的id用hash计算3次,看一下对应位置是否都是1,如果不是,说明数据不存在。
缺点:存在误判率,原因如下
id3的数据不存在,但是因为反hash后的值正好对应id1和id2的某几位数值,导致布隆过滤器认为id3存在。
解决方案:
可以通过扩大数组来减少误判,但是会增加内存消耗
测试代码
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
public class BloomFilterExample {
public static void main(String[] args) {
int size = 1000; // 设置布隆过滤器的大小
double fpp = 0.05; // 设置误判率
// 初始化布隆过滤器
BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.unencodedCharsFunnel(), size, fpp);
// 添加元素
bloomFilter.put("hello");
bloomFilter.put("world");
// 测试元素是否存在
System.out.println(bloomFilter.mightContain("hello")); // true
System.out.println(bloomFilter.mightContain("world")); // true
System.out.println(bloomFilter.mightContain("unknown")); // false
}
}