Redis 缓存穿透, 缓存击穿, 缓存雪崩的解决方案与布隆过滤器
缓存穿透解决方案
设置空值
布隆过滤器
- 优点
- 可以将存在的缓存, 位置设置为1, 然后当不存在的参数过来的时候, 会匹配到0上,这样就会直接返回不存在
- 缺点
- 存在错误判断, hash冲突
- 删除缓存时无法删除指定的1的位置, 应为存在多数据,同一hash, 所以无法删除
- 增加开发成本, 维护成本提高
可以判断一定不存在, 但是不能判断一定存在[存在误判]
使用布隆过滤器
添加依赖
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.1-jre</version> </dependency>
编写代码
package com.dance.redis; import com.google.common.hash.BloomFilter; import com.google.common.hash.Funnels; import org.junit.jupiter.api.Test; import java.nio.charset.Charset; import java.util.stream.IntStream; public class BlTest { @Test public void test(){ // 创建 /** * 数据类型 * 容量 * 误判率 * 容量越大, 误判率越低, 但是使用的内存就越多 * 误判率设置越小, 误判率越低 */ BloomFilter<String> bloomFilter = BloomFilter.create( Funnels.stringFunnel(Charset.defaultCharset()) ,100000 ,0.001 ); // 放入元素 // boolean html = bloomFilter.put("html"); // 判断可能存在 // boolean html1 = bloomFilter.mightContain("html"); // 存放10万数据 IntStream.range(0,200000).forEach(x -> bloomFilter.put(x+"")); int success = 0; int fail = 0; for (int i = 0; i < 10000; i++) { boolean b = bloomFilter.mightContain("test" + i); if (b){ fail++; }else{ success++; } } System.out.println("正确:"+success); System.out.println("错误:"+fail); } }
使用的时候可以根据实际情况, 设置这些阈值
缓存击穿解决方案
- 只让一个请求去查数据库, 其他请求进入CAS自旋, 等待请求返回放入缓存, 然后其他线程去查询缓存
缓存雪崩解决方案
在同一时间点, 缓存大面积失效
解决方案
- 设置热点数据永不过期
- 过期时间分散
- 采用多级缓存
- 采购第三方的Redis(各种云)(花钱解决)