Redis 缓存雪崩、缓存穿透、缓存击穿、缓存预热

缓存雪崩

定义

缓存雪崩是指在短时间内,有大量缓存同时过期,导致大量的请求直接查询数据库,从而对数据库造成了巨大的压力,严重情况下可能会导致数据库宕机的情况叫做缓存雪崩

正常情况下执行过程

Redis 缓存雪崩、缓存穿透、缓存击穿、缓存预热

缓存雪崩下执行过程

Redis 缓存雪崩、缓存穿透、缓存击穿、缓存预热

可以看到,当缓存失效时,大量请求直接绕过 Redis 去请求数据库,导致会对数据库造成很大压力。

解决

加锁排队

加锁排队可以起到缓冲的作用,防止大量的请求同时操作数据库,但它的缺点是增加了系统的响应时间降低了系统的吞吐量,牺牲了一部分用户体验。

思路:当缓存未查询到时,对要请求的 key 进行加锁,只允许一个线程去数据库中查,其他线程等候排队,这里的加锁逻辑就类似于单例模式的双重校验锁。

代码实现

// 缓存 key
String cacheKey = "userlist";
// 查询缓存
String data = jedis.get(cacheKey);
if (StringUtils.isNotBlank(data)) {
    // 查询到数据,直接返回结果
    return data;
} else {
    // 先排队查询数据库,再放入缓存
    synchronized (cacheKey) {
        data = jedis.get(cacheKey);
        if (!StringUtils.isNotBlank(data)) { // 双重判断
            // 查询数据库
            data = findUserInfo();
            // 放入缓存
            jedis.set(cacheKey, data);
        }
        return data;
    }
}

注意:如果是分布式架构,也就是服务集群,不能采用本地锁,必须得使用 Redis 的分布式锁

随机化过期时间

为了避免缓存同时过期,可在设置缓存时添加随机时间,这样就可以极大的避免大量的缓存同时失效。

代码实现

// 缓存原本的失效时间
int exTime = 10 * 60;
// 随机数生成类
Random random = new Random();
// 缓存设置
jedis.setex(cacheKey, exTime + random.nextInt(1000) , value);

设置二级缓存

二级缓存指的是除了 Redis 本身的缓存,再设置一层缓存,当 Redis 失效之后,先去查询二级缓存。

例如可以设置一个本地缓存,在 Redis 缓存失效的时候先去查询本地缓存而非查询数据库。

本地缓存可以使用 GoogleGuava Cache 进行设置,并有容量驱逐、时间驱逐策略,很优秀的一个缓存工具类。

Redis 缓存雪崩、缓存穿透、缓存击穿、缓存预热

其实大部分情况下我们在项目中使用都是先访问本地缓存,然后再访问分布式缓存(Redis),因为访问本地缓存是最快的,没有网络开销,但是需要在一定的时间内进行更新,为了和分布式缓存中的数据保持一致

缓存穿透

定义

缓存穿透是指查询数据库和缓存都无数据,因为数据库查询无数据,出于容错考虑,不会将结果保存到缓存中,因此每次请求都会去查询数据库,这种情况就叫做缓存穿透。

Redis 缓存雪崩、缓存穿透、缓存击穿、缓存预热

解决

使用过滤器

我们可以使用布隆过滤器来减少对数据库的请求,布隆过滤器的原理是将数据库的数据哈希到 bitmap 中,每次查询之前,先使用布隆过滤器过滤掉一定不存在的无效请求,从而避免了无效请求给数据库带来的查询压力

我们可以把每次从数据库查询的数据都保存到缓存中,为了提高前台用户的使用体验 (解决长时间内查询不到任何信息的情况),我们可以将空结果的缓存时间设置得短一些,例如 3~5 分钟。

缓存击穿

定义

缓存击穿指的是某个热点缓存,在某一时刻恰好失效了,然后此时刚好有大量的并发请求,此时这些请求将会给数据库造成巨大的压力,这种情况就叫做缓存击穿。

Redis 缓存雪崩、缓存穿透、缓存击穿、缓存预热

解决

加锁排队

和缓存雪崩的加锁处理方式一致,再查数据库时进行加锁,缓冲大量请求。

设置永不过期

对于某些热点缓存,我们可以设置永不过期,这样就能保证缓存的稳定性,但需要注意在数据更改之后,要及时更新此热点缓存,不然就会造成查询结果的误差。

缓存预热

缓存预热并不是一个问题,而是使用缓存时的一个优化方案,它可以提高前台用户的使用体验。

缓存预热指的是在系统启动的时候,先把查询结果预存到缓存中,以便用户后面查询时可以直接从缓存中读取,以节约用户的等待时间。

Redis 缓存雪崩、缓存穿透、缓存击穿、缓存预热

缓存预热的实现思路有以下三种:

  1. 把需要缓存的方法写在系统初始化的方法中,这样系统在启动的时候就会自动的加载数据并缓存数据。
  2. 把需要缓存的方法挂载到某个页面或后端接口上,手动触发缓存预热。
  3. 设置定时任务,定时自动进行缓存预热。

文章来源:https://www.cnaaa.net,转载请注明出处:https://www.cnaaa.net/archives/6121

(0)
安屠生的头像安屠生
上一篇 2022年11月16日 下午6:11
下一篇 2022年11月17日 下午2:21

相关推荐

  • windows server 2012上安装sql server 2008图文详解

    1.下载sql server 2008镜像文件 2.关闭防火墙 sql server 2008安装过程,检测安装进程会有报错,避免安装失败,这里先关闭防火墙 3.运行并安装程序 选择管理员身份运行 选择运行程序二不获取帮助 进入安装中心后选择 安装,再选择 全新安装 继续选择运行程序而不获取帮助 选择后如图,系统会自动检测系统,没警告说明可以定确定 输入密钥…

    2022年8月4日
    3.8K00
  • 数据库压力测试

    一、前言 在前面的压力测试过程中,主要关注的是对接口以及服务器硬件性能进行压力测试,评估请求接口和硬件性能对服务的影响。但是对于多数Web应用来说,整个系统的瓶颈在于数据库。 原因很简单:Web应用中的其他因素,例如网络带宽、负载均衡节点、应用服务器(包括CPU、内存、硬盘、连接数等)、缓存,都很容易通过水平的扩展(俗称加机器)来实现性能的提高。而对于MyS…

    2023年3月21日
    97100
  • 无法作为数据库主体执行,因为主体 “dbo“ 不存在、无法模拟这种类型的主体,或您没有所需的权限

    问题描述: 最近正在测试数据库复制,想删除发布服务器的发布数据库时,突然提示这个:无法作为数据库主体执行,因为主体 “dbo” 不存在、无法模拟这种类型的主体,或您没有所需的权限。已将数据库上下文更改为 “AdventureWorks2008R2”。 (Microsoft SQL Server,错误: 15517) 原因分析: 用附件文件和组的方法的还原数据…

    2023年2月18日
    1.0K00
  • mysql innodb临时表btmp1文件太大

    某日生产环境(数据库实例)告警,磁盘使用率过高! 检查发现是由于mysql的data目录的ibtmp1文件太大,达到了30GB 一、ibtmp1文件是干嘛的? 就是用来存放临时表查询时的数据。 二、ibtmp1增长的原因是什么?主要与SQL有关,尤其是大量的分组聚合,排序,join查询SQL.通常如下情况会造成iptmp1上涨: 查询语句会先查询temp_t…

    2023年12月18日
    1.3K00
  • 内存耗尽后Redis会发生什么

    前言 作为一台服务器来说,内存并不是无限的,所以总会存在内存耗尽的情况,那么当 Redis 服务器的内存耗尽后,如果继续执行请求命令,Redis 会如何处理呢? 内存回收 使用Redis 服务时,很多情况下某些键值对只会在特定的时间内有效,为了防止这种类型的数据一直占有内存,我们可以给键值对设置有效期。Redis 中可以通过 4 个独立的命令来给一个键设置过…

    2023年7月17日
    80000

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

在线咨询: QQ交谈

邮件:712342017@qq.com

工作时间:周一至周五,8:30-17:30,节假日休息

关注微信