缓存穿透
缓存穿透,指的是查询时,缓存和数据库中都不存在该数据,这样的查询每次都会查询到数据库,会导致数据库的压力过大。
解决方式通常有两种:
- 对数据库中不存在的值也进行缓存,比如对空值在Redis中缓存一个特殊的字符串,比如&(*&(#Q&$&#。
- 布隆过滤器
布隆过滤器
布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量(位图)和一系列随机映射函数(哈希函数)。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
原理
布隆过滤器使用位数组来记录元素是否存在于集合当中。
当一个元素被加入集合时,会使用k个哈希函数分别对其进行计算得到k个哈希值。接着用k个哈希值分别对位数组的长度进行取余,得到k个数组下标,此时会将这k个下标下的值都置为1。
当需要判断一个元素是否在集合中时,使用k个哈希函数分别对其进行计算得到k个哈希值。接着用k个哈希值分别对位数组的长度进行取余,得到k个数组下标,判断这k个下标上的值是否都为1,如果有一个不为1,那么肯定不存在,如果都为1,则存在。
不同的元素可能得到相同的哈希值,所以布隆过滤器存在一定概率的误判,即布隆过滤器说某个元素存在,有概率会误判。
解决缓存穿透
在项目启动后,可以将数据库中的数据添加到布隆过滤器中,当查询缓存不存在时,通过布隆过滤器判断数据库中是否存在,如果不存在就不进行DB查询了,减少数据库的压力。
实现与使用
1. guava实现
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.1-jre</version></dependency>public class BloomFilterUse {private static BloomFilter<Integer> bf = BloomFilter.create(Funnels.integerFunnel(), 1000000);public static void main(String[] args) {for (int i = 0; i < 1000000; i++) {bf.put(i);}int count = 0;for (int i = 1000000; i < 1100000; i++) {if (bf.mightContain(i)) {count++;}}System.out.println(count + "个判断错误");//3033个 约0.03的概率}}
2. redisson实现
public class RedissonBloomFilterUse {public static void main(String[] args) {Config config = new Config();config.useSingleServer().setAddress("redis://127.0.0.1:6379");RedissonClient redissonClient = Redisson.create(config);RBloomFilter<String> goods = redissonClient.getBloomFilter("goods");goods.tryInit(100000L,0.03);goods.add("goods_123123");System.out.println(goods.contains("goods_123123"));}}
