redis缓存穿透及解决方案

redis常用业务场景

 

redis缓存穿透及解决方案_第1张图片

redis缓存穿透及解决方案_第2张图片

redis缓存穿透及解决方案_第3张图片

如何解决缓存穿透带来的问题

如果是多次查询相同不存在的值,可以将该空值也给添加至redis中,并且给失效时间,因为防止后面该条数据会有更新。

问题:如何在海量数据(例如10亿无序,不定长,不重复)快速判断某一元素是否存在?

分析思路:

首先,10亿条数据肯定不能直接去mysql,因为mysql数据是在磁盘上,会很慢。

能否直接放到redis???

也不可以,因为如果全放到redis,就无法保证redis和mysql的数据一致性。

所以我们必须要有个存储的数据的容器,常见的数据结构有:

数组,链表,树,hashMap........

如果一条数据有10kb,那么十亿条数据就有几百G的大小,普通的服务器无法承受。

所以需要找一种最简单的数据结构

布隆过滤器详解

1):数据结构是位数组(二进制向量)

2):一系列随机hash映射函数

redis缓存穿透及解决方案_第4张图片

布隆过滤器根据key通过多次hash算法计算出位数组的下标,根据下标位置判断出是否存在

布隆过滤器结果具有以下特点:

1)如果布隆过滤器判断元素存在,真实结果不一定存在(因为可能会出现hash碰撞)

2)如果布隆过滤器判断不存在,则元素一定不存在

3)如果元素实际存在,则布隆过滤器一定存在

4)如果元素实际不存在,则布隆过滤器可能存在

手撕代码:统计布隆过滤去命中率

        
            com.google.guava
            guava
            21.0
        
import com.google.common.base.Charsets;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;

import java.text.NumberFormat;
import java.util.*;

public class BloomFilterDemo {
    //模拟一共有100万条数据
    private static final int count = 1000000;

    public static void main(String[] args) {
        BloomFilter bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), count);
        //实际存在的key,取出使用
        List list = new ArrayList();
        //实际存在的key,判断是否存在
        Set set = new HashSet();
        for (int i = 0; i < count; i++) {
            String uuid = UUID.randomUUID().toString();
            list.add(uuid);
            set.add(uuid);
            bloomFilter.put(uuid);
        }
        //正确判断的次数
        int right = 0;
        //错误判断的次数
        int error = 0;
        for (int i = 0; i < 10000; i++) {
            String data = i % 100 == 0 ? list.get(i) : UUID.randomUUID().toString();
            if (bloomFilter.mightContain(data)) {
                if (set.contains(data)) {
                    right++;
                    continue;
                }
                error++;
            }
        }
        NumberFormat percentInstance = NumberFormat.getPercentInstance();
        percentInstance.setMinimumFractionDigits(2);
        float wrong = (float) error / 9900;
        float bingo = (float) (9900-wrong) / 9900;
        System.out.println("判断100个元素存在的数据,布隆过滤器认为存在的有:"+right+"\t"
        +"判断9900个元素不存在的数据,布隆过滤器认为不存在的有:"+error+"\t命中率为:"+percentInstance.format(bingo)
                +"误判率为:"+percentInstance.format(wrong));
    }

运行结果:

判断100个元素存在的数据,布隆过滤器认为存在的有:100	判断9900个元素不存在的数据,布隆过滤器认为不存在的有:290	命中率为:100.00%误判率为:2.93%

1:离线数据加载到布隆过滤器

2:布隆过滤器查询

3:过滤器不存在,则直接返回

4:过滤器存在,cache不存在,从数据库查询

5:数据库返回

你可能感兴趣的:(redis)