redis缓存穿透及解决方案

redis常用业务场景

 

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

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

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

分析思路:

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

能否直接放到redis???

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

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

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

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

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

布隆过滤器详解

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

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

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

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

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

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

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

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

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

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>21.0</version>
        </dependency>
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<CharSequence> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), count);
        //实际存在的key,取出使用
        List<String> list = new ArrayList<String>();
        //实际存在的key,判断是否存在
        Set<String> set = new HashSet<String>();
        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:数据库返回

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值