Redis缓存穿透、缓存雪崩问题分析

Redis缓存穿透、缓存雪崩问题分析把redis作为缓存使用已经是司空见惯,但是使用redis后也可能会碰到一系列的问题,尤其是数据量很大的时候,经典的几个问题如下:(一)缓存和数据库间数据一致性问题分布式环境下(单机就不用说了)非常容易出现缓存和数据库间的数据一致性问题,针对这一点的话,只能说,如果你的项目对缓存的要求是强一致性的,那么请不要使用缓存。我们只能采取合适的策略来降低缓存和数据库间数据不一致的概率,而无法保证两…

大家好,又见面了,我是你们的朋友全栈君。

把redis作为缓存使用已经是司空见惯,当redis中的数据量起来了以后你就得考虑以下几个问题:

(一)缓存和数据库间数据一致性问题

分布式环境下(单机就不用说了)非常容易出现缓存和数据库间的数据一致性问题,针对这一点的话,只能说,如果你的项目对缓存的要求是强一致性的,那么请不要使用缓存。我们只能采取合适的策略来降低缓存和数据库间数据不一致的概率,而无法保证两者间的强一致性。合适的策略包括 合适的缓存更新策略,更新数据库后要及时更新缓存、缓存失败时增加重试机制,例如MQ模式的消息队列。


()缓存穿透问题

现象:用户大量并发请求的数据(key)对应的数据在redis和数据库中都不存在,导致尽管数据不存在但还是每次都会进行查DB。

为什么key对应数据在缓存和db中不存在还会每次都进行DB查询呢?因为很多开发同学写的代码写的逻辑都是先从redis缓存中查一把,如果缓存中为空则从DB中查,如果DB中查到的数据不为空则设置到缓存并返回给接口。那么问题来了,如果从DB中查询的数据为空呢??

解决方案

  • 从DB中查询出来数据为空,也进行空数据的缓存,避免DB数据为空也每次都进行数据库查询;
  • 使用布隆过滤器,但是会增加一定的复杂度及存在一定的误判率;

bloomfilter就类似于一个hash set,用于快速判某个元素是否存在于集合中,其典型的应用场景就是快速判断一个key是否存在于某容器,不存在就直接返回。布隆过滤器的关键就在于hash算法和容器大小,下面先来简单的实现下看看效果,我这里用guava实现的布隆过滤器:

<dependencies>  
     <dependency>  
         <groupId>com.google.guava</groupId>  
         <artifactId>guava</artifactId>  
         <version>23.0</version>  
     </dependency>  
</dependencies>  
public class BloomFilterTest {

    private static final int capacity = 1000000;
    private static final int key = 999998;

    private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), capacity);

    static {
        for (int i = 0; i < capacity; i++) {
            bloomFilter.put(i);
        }
    }

    public static void main(String[] args) {
        /*返回计算机最精确的时间,单位微妙*/
        long start = System.nanoTime();

        if (bloomFilter.mightContain(key)) {
            System.out.println("成功过滤到" + key);
        }
        long end = System.nanoTime();
        System.out.println("布隆过滤器消耗时间:" + (end - start));
        int sum = 0;
        for (int i = capacity + 20000; i < capacity + 30000; i++) {
            if (bloomFilter.mightContain(i)) {
                sum = sum + 1;
            }
        }
        System.out.println("错判率为:" + sum);
    }
}
成功过滤到999998
布隆过滤器消耗时间:215518
错判率为:318

可以看到,100w个数据中只消耗了约0.2毫秒就匹配到了key,速度足够快。然后模拟了1w个不存在于布隆过滤器中的key,匹配错误率为318/10000,也就是说,出错率大概为3%,跟踪下BloomFilter的源码发现默认的容错率就是0.03:

public static <T> BloomFilter<T> create(Funnel<T> funnel, int expectedInsertions /* n */) {
  return create(funnel, expectedInsertions, 0.03); // FYI, for 3%, we always get 5 hash functions
}

我们可调用BloomFilter的这个方法显式的指定误判率:

Redis缓存穿透、缓存雪崩问题分析

private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), capacity,0.01);

我们断点跟踪下,误判率为0.02和默认的0.03时候的区别:

Redis缓存穿透、缓存雪崩问题分析

Redis缓存穿透、缓存雪崩问题分析

对比两个出错率可以发现,误判率为0.02时数组大小为8142363,0.03时为7298440,误判率降低了0.01,BloomFilter维护的数组大小也减少了843923,可见BloomFilter默认的误判率0.03是设计者权衡系统性能后得出的值。要注意的是,布隆过滤器不支持删除操作。用在这边解决缓存穿透问题就是:

public String getByKey(String key) {
    // 通过key获取value
    String value = redisService.get(key);
    if (StringUtil.isEmpty(value)) {
        if (bloomFilter.mightContain(key)) {
            value = userService.getById(key);
            redisService.set(key, value);
            return value;
        } else {
            return null;
        }
    }
    return value;
}

(三)缓存雪崩问题

现象:大量key同一时间点失效,同时又有大量请求打进来,导致流量直接打在DB上,造成DB不可用。

解决方案

  • 设置key永不失效(热点数据);
  • 设置key缓存失效时候尽可能错开;
  • 使用多级缓存机制,比如同时使用redsi和memcache缓存,请求->redis->memcache->db;
  • 购买第三方可靠性高的Redis云服务器;

books 引申阅读: 使用quartz实现高级定制化定时任务(包含管理界面)

books 推荐阅读:elastic search搜索引擎实战demo:https://github.com/simonsfan/springboot-quartz-demo,分支:feature_es

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/147755.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 支持向量机原理与实现的区别_支持向量机实例

    支持向量机原理与实现的区别_支持向量机实例一、模型机器学习中我们最开始接触的都是感知机,感知机就是一个阶跃函数,阶跃函数的自变量是一个多元线性函数,costfunction则是。而支持向量与感知机类似,只是将阶跃函数挖去(-1到1这个区间),要使两个平行的超平面间间隔最大,只需w二范数最小即可。约束条件是.关于约束条件的理解,取等号时刚好在支持向量上,不取等号时说明在平面的对应的一侧。理解了问题的本质,现在就是怎么用数学去解决这…

    2022年10月21日
  • redis版本怎么查看(查看redis进程)

    1下载redis并且解压https://www.runoob.com/redis/redis-install.html2分别启动服务端和客户端3在服务端输入info命令,可以看到当前版本

  • linux的vim怎么剪切,Linux.vim.多行复制、删除、剪切

    linux的vim怎么剪切,Linux.vim.多行复制、删除、剪切中间件Study-了解什么是中间件一.中间件含义:中间价是位于各种平台(硬件和操作系统)和各种应用之间的通用服务.帮助应用实现高效的.可靠的消息使应用之间实现便捷的互联互通高效.可靠构建企业应用实现分布式应用的快速搭建和部署注:中间…谈谈我印象中的JVM不足之处研究JVM也有一段时间了,其间也发现了它的很多不足之处,在此一一道来,由于本人对JVM的理解有限,如有错误的地方,还请大家指正:本…

  • RPC是什么? (学习笔记)

    RPC是什么? (学习笔记)什么是RPC?RPC全称RemoteProcedureCall,即远程过程调用,就是要像调用本地的函数一样去调远程函数,屏蔽远程调用的复杂性。为什么需要RPC?微服务、分布式应用的开发越来越

  • sql 日期格式汇总

    sql 日期格式汇总

    2021年11月26日
  • OpenCV 估算图像的投影关系:基础矩阵和RANSAC[通俗易懂]

    OpenCV 估算图像的投影关系:基础矩阵和RANSAC[通俗易懂]OpenCV 估算图像的投影关系:基础矩阵和RANSAC

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号