缓存穿透分析

110 阅读2分钟

总结一下之前项目的使用🐕🐕🐕

什么是缓存穿透

缓存穿透是指在使用缓存系统时,恶意或频繁地请求一个不存在于缓存中的数据,导致每次请求都需要查询数据库或其他数据存储系统,从而绕过了缓存的效果,严重影响系统性能。

这种情况通常发生在恶意攻击、大量请求缓存中不存在的数据或缓存数据过期后的高并发访问。

常见的解决方案

  1. 对不存在的 Key 进行缓存,值设为 Null,并设置短暂过期时间,如 60 秒。
  2. 使用布隆过滤器,将所有已注册的用户名存入布隆过滤器,判断时先判断该用户名是否在布隆过滤器中,不在的一定不存在,避免直接查询数据库。
  3. 使用确定的数据结构如 Redis 的 Set 集合来存储已注册用户名,判断时检查是否在集合内。
  4. 针对高并发注册场景,可以先查询缓存,如果不命中则使用分布式锁来保证只有一个线程访问数据库,避免重复查询

下面是上面的方案一一对应的问题:

  • 对不存在的key进行缓存,对用户不友好
  • 布隆过滤器不能删除元素的限制,导致该方案无法正式使用生产
  • 占用大量的内存资源,并且复杂度变高,总不能保存在一个key中
  • 成本高,用户体验不好

最终解决

布隆过滤器+一层缓存

image.png

布隆过滤器的使用

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
    }
}