缓存击穿、缓存穿透、缓存雪崩是使用Redis的三个经典问题,上篇文章讲了缓存击穿,今天就讲下剩下的两个问题。

一、缓存穿透

定义:缓存穿透是指查询一个根本不存在的数据,缓存层和DB层都不会命中。这样缓存永远不会生效,这些请求最终都会访问数据库。引起DB的压力瞬间变大,导致服务不可用。

问题:试想一个场景,正常来说,某个直播间的相关信息都是会缓存到Redis或者服务器的本地缓存中(提一嘴,我们有些并发量极高的数据是直接缓存在服务器的本地缓存中的,而不是缓存在Redis,因为Redis对于服务器来说是属于第三方组件,连接是耗时的,无论如何也比不过本地缓存。当然服务器本地缓存数据就需要每一台机器都缓存一份数据,就是空间换时间的概念,这个根据实际业务来衡量来采取哪种方案),而此时假设前端有一个异常请求,请求一个不存在的直播ID,那么我们首先会去查缓存,然后缓存没有,我们就会去查DB。好了,问题来了,假设前端伪造了N个这样的请求,那是不是N个请求都要去查DB,那么DB怎么可能扛得住啊。我们之前线上就出现过这样的问题,被恶意攻击了,血泪教训啊。

解决方案

解决缓存穿透问题有几种方案:

1、布隆过滤器。通过在前端部署一个布隆过滤器,可以预先判断该键很可能不存在于数据库中,然后将其拦截,从而避免对数据库发起无效请求。但是这玩意维护成本太高了,对于我们的业务来说,这很明显是还用不上的。感兴趣的同学可以去了解下,这里我就不细讲了。

2、对明显有问题的前端传参进行过滤,比如,假设直播ID是64长度的字符串,那么后端可以对不满足64位的请求直接给过滤掉,不处理。当然,这种小把戏自然是挡不住黑客的,人家搞一堆64位的字符串长度的直播ID不分分钟的事吗

3、设置空缓存,比如,虽然数据库中没有直播ID为“xxxx”的数据,但是在Redis中对其进行缓存(key=xxxx, value=null),这样当请求到达Redis的时候就会直接返回一个null的值给客户端,避免了大量无法访问的数据直接打在DB上。不过得注意,设置这种空缓存的时间不能设置过长,不然有恶意请求的时候,这种空缓存也会引起Redis存储空间暴涨。这个就是我们常用来处理缓存穿透问题的有效方案。 demo样例如下:

	rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "123456",
DB: 0,
}) err := rdb.Set(ctx, "xxxx", "null", 5*60).Err()
if err != nil {
panic(err)
}

二、缓存雪崩

定义:当Redis中的大量key集体过期或失效,这时候如果有大量并发的请求来到,Redis就无法进行有效的响应,所有的查询都落在数据库上,就会出现缓存雪崩。

问题:假设一个场景,我们的直播Redis机器在晚高峰时候出现了宕机,然后进行了重启,那么此时大量的前端请求就会进来,都会去读Redis。但是我重启之后,所以key值都被干掉了啊,那么这时所有的请求查Redis都得不到响应(太惨了),都需要重建缓存。这时候就会触发传说中的缓存雪崩(机器崩,人也差不多崩了)。当然,这是比较极端的一种场景。还有另一种情况就是使用了主动缓存(通过脚本或者定时任务等去生成缓存),然后设置的时间很集中,出现同时过期的时候,也会出现缓存雪崩问题。

解决方案

解决缓存雪崩问题有几种方案:

1、给缓存失效时间设置一些随机值,让缓存尽量的打散,不要集中在一个时间失效。其实大部分业务场景缓存时间都是打散的了,我们只需要使用的时候多留意一下即可。

2、使用Redis集群,当一台宕机之后,还有备用节点,可以将请求打到正常工作的节点中。

总的来说,缓存穿透和缓存雪崩问题带来的最终结果都是灾难性的,但是个人认为这两个在正常业务中,都是比较可控的,除非一些异常场景,例如被恶意攻击等行为。

go高并发之路——缓存穿透、缓存雪崩的更多相关文章

  1. redis的缓存穿透 缓存并发 缓存失效

    我们在用缓存的时候,不管是Redis或者Memcached,基本上会通用遇到以下三个问题: 缓存穿透 缓存并发 缓存失效 一.缓存穿透 Paste_Image.png Paste_Image.png ...

  2. Redis中几个简单的概念:缓存穿透/击穿/雪崩,别再被吓唬了

    Redis中几个“看似”高大上的概念,经常有人提到,某些好事者喜欢死扣概念,实战没多少,嘴巴里冒出来的全是高大上的名词,个人一向鄙视概念党,呵呵! 其实这几个概念:缓存穿透/缓存击穿/缓存雪崩,有一个 ...

  3. Java Redis缓存穿透/缓存雪崩/缓存击穿,Redis分布式锁实现秒杀,限购等

    package com.example.redisdistlock.controller; import com.example.redisdistlock.util.RedisUtil; impor ...

  4. Redis 17 缓存穿透 缓存击穿 缓存雪崩

    参考源 https://www.bilibili.com/video/BV1S54y1R7SB?spm_id_from=333.999.0.0 版本 本文章基于 Redis 6.2.6 使用缓存的问题 ...

  5. 缓存穿透 & 缓存击穿 & 缓存雪崩

    参考文档: 缓存穿透和缓存失效的预防和解决:https://blog.csdn.net/qq_16681169/article/details/75138876 缓存穿透 缓存穿透是指查询一个一定不存 ...

  6. redis缓存穿透,缓存击穿,缓存雪崩

    缓存穿透 缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有.这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询).这样请求就会绕过 ...

  7. 缓存穿透、雪崩、热点与Redis

    (拼多多问:Redis雪崩解决办法) 导读:互联网系统中不可避免要大量用到缓存,在缓存的使用过程中,架构师需要注意哪些问题?本文以 Redis 为例,详细探讨了最关键的 3 个问题. 一.缓存穿透预防 ...

  8. 什么是redis缓存穿透, 缓存雪崩, 缓存击穿

    什么是redis? redis是一个非关系型数据库,相对于其他数据库而言,它的查询速度极快,且能承受的瞬时并发量非常的高.所以常常被用来存放网站的缓存,以减少主要数据库(如mysql)的服务器压力. ...

  9. Redis系列(八)--缓存穿透、雪崩、更新策略

    1.缓存更新策略 1.LRU/LFU/FIFO算法剔除:例如maxmemory-policy 2.超时剔除,过期时间expire,对于一些用户可以容忍延时更新的数据,例如文章简介内容改了几个字 3.主 ...

  10. 缓存穿透 & 缓存雪崩 & 缓存击穿

    一 缓存穿透 1. 行为 查询一个一定不存在的数据.存储层(姑且认为是db,下面都用db指代)查不到数据则不写入缓存,那么下次请求这个不存在的数据同样会到db层查询,失去了缓存的意义.流量大或人为恶意 ...

随机推荐

  1. Python 布尔类型

    布尔值表示两个值之一:True(真)或False(假). 布尔值 在编程中,您经常需要知道一个表达式是否为True或False. 您可以在Python中评估任何表达式,并获得两个答案之一:True或F ...

  2. 如何在openGauss 2.1.0中使用Job

    如何在 openGauss 2.1.0 中使用 Job 如何在 openGauss 2.1.0 中使用 Job Job 类似 unix 中的 crontab,有定时执行的功能,可以在指定的时间点或每天 ...

  3. 重新点亮shell————测试命令[六]

    前言 我们写好脚本之后希望有一个测试. 正文 介绍一下exit,如果exit 0,那么表示正常退出. 如果exit 10,也就是非0,那么就是异常退出. 然后这个test 标准为[]和 [[]]这样子 ...

  4. linux 允许root 用户登录(旧)

    前言 旧博客迁移的内容 正文 vi /etc/ssh/sshd_config 将PermitRootLogin值改yes service sshd restart

  5. js es6 介绍set,WeakSet

    前言 介绍一下es6 的set 和 weakset 正文 set ES6 提供了新的数据结构 Set.它类似于数组,但是成员的值都是唯一的,没有重复的值. Set 本身是一个构造函数,用来生成 Set ...

  6. FPGA技术脚本使用

    做fpga 不会脚本,基本跟残废一个概念.以前我觉得做FPGA应该学习什么人工智能,大数据,机器人.现在想起来真是傻逼,做fpga也好,做ic,做逻辑其实基本能力都是一样的. 一个学习tcl脚本,pe ...

  7. D365调试进入系统类方法

    在生成InventDIMID时,虽然设置了InventDIMID的Number sequence为自定义的Format,但是总是不按指定的Number sequence产生InventDIMID Di ...

  8. Oracle常用的创建表语句

    Oracle常用的创建表语句 Oracle常用的创建表语句 指定字段的创建 --指定字段的创建 create table table_name( test_1(字段名1) varchar2(50),( ...

  9. 力扣682(java)-棒球比赛(简单)

    题目: 你现在是一场采用特殊赛制棒球比赛的记录员.这场比赛由若干回合组成,过去几回合的得分可能会影响以后几回合的得分. 比赛开始时,记录是空白的.你会得到一个记录操作的字符串列表 ops,其中 ops ...

  10. C++ 访问说明符详解:封装数据,控制访问,提升安全性

    C++ 访问说明符 访问说明符是 C++ 中控制类成员(属性和方法)可访问性的关键字.它们用于封装类数据并保护其免受意外修改或滥用. 三种访问说明符: public:允许从类外部的任何地方访问成员. ...