总结一下之前项目的使用🐕🐕🐕
什么是缓存穿透
缓存穿透是指在使用缓存系统时,恶意或频繁地请求一个不存在于缓存中的数据,导致每次请求都需要查询数据库或其他数据存储系统,从而绕过了缓存的效果,严重影响系统性能。
这种情况通常发生在恶意攻击、大量请求缓存中不存在的数据或缓存数据过期后的高并发访问。
常见的解决方案
- 对不存在的 Key 进行缓存,值设为 Null,并设置短暂过期时间,如 60 秒。
- 使用布隆过滤器,将所有已注册的用户名存入布隆过滤器,判断时先判断该用户名是否在布隆过滤器中,不在的一定不存在,避免直接查询数据库。
- 使用确定的数据结构如 Redis 的 Set 集合来存储已注册用户名,判断时检查是否在集合内。
- 针对高并发注册场景,可以先查询缓存,如果不命中则使用分布式锁来保证只有一个线程访问数据库,避免重复查询
下面是上面的方案一一对应的问题:
- 对不存在的key进行缓存,对用户不友好
- 布隆过滤器不能删除元素的限制,导致该方案无法正式使用生产
- 占用大量的内存资源,并且复杂度变高,总不能保存在一个key中
- 成本高,用户体验不好
最终解决
布隆过滤器+一层缓存
布隆过滤器的使用
import cn.hutool.core.util.BloomFilter;
import java.util.ArrayList;
import java.util.List;
public class BloomFilterExample {
public static void main(String[] args) {
// 创建一个布隆过滤器,预计插入1000个元素,误判率0.01%
BloomFilter<String> bloomFilter = BloomFilter.create(1000, 0.01);
// 向布隆过滤器中添加元素
List<String> items = new ArrayList<>();
items.add("apple");
items.add("banana");
items.add("orange");
for (String item : items) {
bloomFilter.put(item);
}
// 测试布隆过滤器
System.out.println(bloomFilter.test("apple")); // 应该返回true,因为"apple"被添加过
System.out.println(bloomFilter.test("grape")); // 可能返回true(假阳性),因为"grape"未被添加过
// 检查布隆过滤器是否包含某个元素
System.out.println(bloomFilter.exists("banana")); // 应该返回true
System.out.println(bloomFilter.exists("lemon")); // 可能返回true
}
}