问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Redis缓存穿透问题及布隆过滤器解决方案

创作时间:
作者:
@小白创作中心

Redis缓存穿透问题及布隆过滤器解决方案

引用
CSDN
1.
https://blog.csdn.net/qq_43620216/article/details/140337163

什么是缓存穿透

缓存穿透是指查询一个不存在的数据,由于MySQL查询不到的数据也不会直接写入缓存,导致每次请求都直接访问数据库。正常情况下,如果数据存在,系统会先从缓存中获取数据,如果缓存中没有,则从数据库中获取并存入缓存。但当查询的数据不存在时,每次请求都会直接访问数据库,造成缓存穿透。

解决方案

方案一:缓存空数据

将不存在的数据也缓存到Redis中,即缓存空数据。

优点:实现简单。

缺点:会消耗额外的内存空间。如果该数据后续有了实际值,从缓存中取到的还是空数据,会发生数据不一致问题。

方案二:布隆过滤器

布隆过滤器是一种空间效率极高的概率数据结构,用于判断一个元素是否在一个集合中。其特点是:

  • 可以判断一个元素是否可能在集合中
  • 不会误判不存在的元素
  • 会误判存在的元素(即存在一定的误判率)

布隆过滤器算法原理

  1. 将数据id通过hash函数计算多次,得到多个位数。
  2. 将这些位数在位数组中标记为1。
  3. 当需要判断一个id是否存在时,同样通过hash函数计算多次,检查对应位是否都为1。如果都为1,则认为该id可能存在;如果有一个位为0,则可以确定该id不存在。

缺点:存在误判率。如下图所示,id3的数据实际上不存在,但由于反hash后的值正好对应id1和id2的某几位数值,导致布隆过滤器认为id3存在。

解决方案:可以通过扩大位数组的大小来减少误判率,但这会增加内存消耗。

布隆过滤器Java实现示例

以下是使用Google Guava库实现布隆过滤器的示例代码:

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

通过布隆过滤器,可以在一定程度上避免缓存穿透问题,同时控制误判率在可接受范围内。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号