前言

  从学校出来,做开发工作也有一定时间了,最近有想系统地进一步深入学习,但发现基础知识不够扎实,故此来回顾基础知识,进一步巩固、加深印象。

  最初开始接触编程时,总是自己跌跌撞撞、不断摸索地去学习,再一点点应用到实际项目中,知识点才更加清晰。后来,尝试写博客,把学到的知识试着分享出来,也是一次巩固的过程。

1、问:Redis雪崩了解吗?

  答:我了解的。目前电商首页以及热点数据都会去做缓存,一般缓存都是定时任务去刷新,或者是查不到之后去更新,定时任务刷新就有一个问题。

  举个简单例子:如果所有首页的key失效时间都是12小时,中午12点刷新,我0点开始抢单活动,大量用户涌入,假设当时每秒6000个请求,本来缓存可以扛住每秒5000个请求,但是缓存当时所有的 Key 都失效了。此时,1秒 6000个请求全部打到数据库,数据库必然扛不住,它会报一下警,但实际情况可能是DBA都没反应过来数据库就直接挂了。此时,如果没有什么特别的方案来处理这个故障,DBA很着急,重启数据库,但是数据库马上又被新的流量打死了。这就是我理解的缓存雪崩。

  同一时间缓存大面积失效,那一瞬间Redis跟没有一样,这个数量界别的请求直接打到数据库几乎是灾难性的。试想一下,如果打挂的是一个用户服务的库,那其他依赖它的库所有的接口几乎都会报错,如果没有做熔断等策略,基本上就是一瞬间挂一片的节奏,任你怎么重启用户都会把你打挂,等你重启好的时候,用户早睡觉去了,并且对我们的产品失去了信息。

2、问:那遇到这种情况,你是怎么去应对的?

  答:处理缓存雪崩相对简单,在批量往Redis存数据的时候,把每个Key的失效时间都加个随机值就好,这样就可以保证数据不会在同一时间大面积失效,我相信,Redis这点流量还是顶得住的。

setRedis( Key, value, time+Math.random() * 1000 );
  如果Redis是集群部署,将热点数据均匀分布在不同的Redis库中也能避免全部失效问题,不过在生产环境中操作集群的时候,单个服务都是对应的单个Redis分片,是为了方便数据的管理,但是也同样有可能回失效这样的弊端,失效时间随机是个好策略。

  或者设置热点数据永远不过期,用更新操作就更新缓存就好了(比如运维更新了首页商品,那你刷下缓存就完事了,不要设置过期时间),电商首页的数据也可以用这个操作,保险。

3、问:那你了解缓存穿透和击穿吗?跟雪崩有什么区别?

  答:有了解的。先说说缓存穿透吧。缓存穿透是指缓存和数据库中都没有数据,而用户不断发起请求,我们数据库的 id 都是1开始自增上去的,如果发起 id = -1 的数据 或 id 为特别大(不存在)的数据,这是用户就很可能是攻击者,攻击会导致数据库压力过大,严重会击垮数据库。

  小点的单机系统,可能用 postman 就能搞死,比如自己买的云服务。


  像这种没有对参数进行校验,数据库 ID 都是大于0的,我们一直用小于 0 的参数去请求,每次都能绕开Redis直接打到数据库,数据库也查不到,每次都这样,并发高点就容易崩掉了。

  至于缓存击穿嘛,这个和缓存雪崩有点像,但是又有点区别,缓存雪崩是因为大面积的缓存失效,打崩了DB,而缓存击穿不同的是缓存击穿是指一个Key非常热点,在不停地扛着大并发,大并发集中对一个点进行访问,当这个Key在失效的瞬间,持续的大并发就穿透缓存,直接请求数据库,就像一个完好无损的桶上凿开了一个洞。比如系统中某个商品,突然变成爆款,大量用户访问该商品,就可能发生缓存击穿。

4、问:雪崩、穿透、击穿你们都是怎么解决的?

  答:缓存穿透是请求绕过缓存直接查数据库,我会在接口层增加校验,比如对用户权限校验,接口参数做校验,不合法的参数直接Return,比如 id 做基础校验,id<=0的直接拦截等等。

  (这里我想补充一点,就是我们在开发的时候,要保持一颗“不信任”的心,就是不要相信任何调用方,比如我提供API接口出去,我需要这几个入参,那作为被调用方,任何可能的参数情况都应该被考虑到、并做校验,因为我不相信调用我接口的人,我不知道他会传什么参数给我。

  举个简单例子,我这个接口是分页查询的,但是我没有对分页参数的大小做限制,调用的人万一 一口气查 Interger.MAX_VALUE  一次请求就需要我几秒,多几个并发我接口就挂了。是公司同事调用还好,大不了发现了改掉就是了,但是如果是黑客或者竞争对手,那问题就大了。在双十一或者抢单活动的时候调用这个接口,那损失就大了。)

  从缓存取不到的数据,在数据库中也没有取到(不管是数据不存在,还是系统故障),这时也可以将对应Key的Value对写为null、“位置错误”、“稍后重试”这样的值(具体和产品沟通),或者看具体的场景,缓存的时间可以设置短点,如30秒(设置太长会导致正常情况下也没法适用),这样第二次到缓冲中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴

  这样可以防止攻击用户反复用同一个 id 暴力攻击,但是我们要知道正常用户是不会在单秒内发起这么多次请求的,那网关层Nginx 我们也可以添加配置项,可以让运维人员对单个 IP 每秒访问次数超出阀值的 IP 都拉黑。

5、问:还有其他办法吗?

  答:记得Redis还有一个高级用法布隆过滤器(Bloom Filter),这个也能很好地防止缓存穿透的发生,他的原理也很简单,就是利用高效的数据结构和算法快速判断出你这个Key是否在数据库中存在,不存在你Return就好了,存在你就去查了DB刷新Key、Value,再Return。

  缓存击穿的话,设置热点数据永远不过期,或者加上互斥锁就能搞定了。(代码如下)

 /**
* 获取数据
* @param key 查询参数
* @return data 数据
* @throws InterruptedException 异常
* @author 柠檬先生
*/
public static String getData(String key) throws InterruptedException {
// 从redis查询数据
String result = getDataFromKV(key);
// 校验数据
if (StringUtils.isBlank(result)){
// 获取锁
if (reenLock.tryLock()) {
// 去数据库查询
result = getDataFromDB(key);
// 校验
if (StringUtils.isNotBlank(result)){
// 保存到缓存中;
setDataToKV(key, result);
}
// *释放锁 正常会再finally里面释放;
reenLock.unLock();
}else {
// 睡一会儿再拿
Thread.sleep(100L);
result = getData(key);
}
}
return result;
}
//这里的锁是单机版玩法.,分布式锁还是得靠lua脚本这样的;

小结:

  以上介绍了Redis的雪崩、击穿、穿透,三者其实都差不多,但是又有些区别,在面试中这是问到缓存必问的,因为缓存的雪崩、击穿、穿透,是缓存最大的问题,要么不出现,一旦出现就是致命性的问题,所以面试官一定会问。

  我们学习的时候一定要理解是怎么发生,以及怎么去避免的,发生之后怎么去抢救,你可以不是了解很深入,但是你一定不能什么都不去想,面试有时候不一定是对只是面的拷问,或许是对你态度的拷问,如果你思路清晰,然后知其然还能知其所以然那就更棒了,还能知道怎么预防,那offer就是手到擒来了。

总结:

  一般避免以上情况发生我们要从3个时间段去分析:

  • 事前:Redis 高可用,主从+哨兵,Redis cluster,避免全盘崩溃;
  • 事中:本地 ehcache 缓存 + Hystrix 限流 + 降级,避免 **MySQL** 被打死。
  • 事后:Redis 持久化 RDB + AOF,一旦重启,自动从磁盘上加载数据,快速回复缓存数据。

  上面提到的限流组件,可以设置每秒的请求,有多少能通过组件,剩余未通过的请求,怎么办?走降级!可以返回一些默认值,或者友情提示,或者空白的值。

  这样做的好处是:数据库绝对不会死,限流组件确保了每秒只有多少个请求能通过。只要数据库不死,对用户来说, 3/5 的请求都是可以被处理的。只要有 3/5 的请求可以被处理,就意味着系统没有死,对用户来说,可能就是点击几次刷不出来页面,但是多点几次就可以刷出来一次。

  这个在目前主流的互联网大厂里面是最常见的,以前遇到过,某明星爆出什么事情,会发现微博怎么刷都是空白界面,但是有的人有直接进去了,多刷几次又出来了,这就是做了降级,牺牲部分用户体验来换取服务器的安全,还行。

  还有就是今年(2019)的双十一,走的就是“限流、降级”,下单接口其实没有挂,牺牲部分用户体验,保住服务器,你多点几下是可以成功的,等流量高峰过去了,所有的用户全部都恢复正常访问,服务器啥事也没有。

  去年(2018)退款接口被打崩了,今年阿里也聪明了很多,退款接口在12日0点开放,这就有效避开了流量高峰。

Redis系列三 - 缓存雪崩、击穿、穿透的更多相关文章

  1. (转)面试前必知Redis面试题—缓存雪崩+穿透+缓存与数据库双写一致问题

    背景:redis问题在面试过程中经常被问到,对于常见问题一定不能放过. 面试前必知Redis面试题—缓存雪崩+穿透+缓存与数据库双写一致问题 一.缓存雪崩 1.1什么是缓存雪崩? 如果缓存数据设置的过 ...

  2. Redis 面试常见问题———缓存雪崩、缓存击穿以及缓存穿透

    在开发中会面临缓存异常可能会出现三个问题,分别是缓存雪崩.缓存击穿和缓存穿透.这三个问题会导致大量请求从缓存转移到数据库,如果请求的并发量很大的话,就会导致数据库崩溃.所以在面试官也会经常问这些问题. ...

  3. redis缓存雪崩、穿透、击穿概念及解决办法

    缓存雪崩 对于系统 A,假设每天高峰期每秒 5000 个请求,本来缓存在高峰期可以扛住每秒 4000 个请求,但是缓存机器意外发生了全盘宕机.缓存挂了,此时 1 秒 5000 个请求全部落数据库,数据 ...

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

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

  5. Redis 缓存雪崩、穿透、击穿

    缓存雪崩 定义: 同一时间所有 key 大面积失效,比如网站首页的数据基本上都是同一批次去缓存的. 解决方法: ① 存的时候设定随机的失效时间. ② 服务做熔断处理(异常或着慢查询 Hystrix 限 ...

  6. 面试前必知Redis面试题—缓存雪崩+穿透+缓存与数据库双写一致问题

    今天来分享一下Redis几道常见的面试题: 如何解决缓存雪崩? 如何解决缓存穿透? 如何保证缓存与数据库双写时一致的问题? 一.缓存雪崩 1.1什么是缓存雪崩? 回顾一下我们为什么要用缓存(Redis ...

  7. 缓存雪崩、穿透如何解决,如何确保Redis只缓存热点数据?

    缓存雪崩如何解决? 缓存穿透如何解决? 如何确保Redis缓存的都是热点数据? 如何更新缓存数据? 如何处理请求倾斜? 实际业务场景下,如何选择缓存数据结构 缓存雪崩 缓存雪崩简单说就是所有请求都从缓 ...

  8. 关于redis的几件小事(七)redis缓存雪崩与穿透

    1.缓存雪崩 (1)什么是缓存雪崩 缓存雪崩指的是在同一时刻,缓存大量失效,导致大量的请求直接到了数据库,数据库压力剧增,引起系统崩溃.可能出现的情况有: ①大量的key设置了相同的过期时间,导致在缓 ...

  9. Redis中的缓存雪崩与缓存穿透

    1.缓存雪崩 1.1什么是缓存雪崩? 如果我们的缓存挂掉了,这意味着我们的全部请求都跑去数据库了. 我们都知道Redis不可能把所有的数据都缓存起来(内存昂贵且有限),所以Redis需要对数据设置过期 ...

随机推荐

  1. RELAX NG

    RELAX NG (读作"relaxing"), 是一种基于语法的XML模式语言,可用于描述.定义和限制XML词汇表. 最初的XML模式语言是DTD,但是因为DTD语法丑陋, 表达 ...

  2. id NSObject instanceType 区别

    id 当不确定数组元素类型时,可以选择使用id NSObject和id都可以指向任何对象 NSObject使用时必须强转 instantceType 只能返回和方法所在类相同类型的对象    返回值类 ...

  3. HTTP协议八种请求类型介绍

    HTTP 协议中共定义了八种方法或者叫“动作”来表明对 Request-URI 指定的资源的不同操作方式,具体介绍如下: OPTIONS:返回服务器针对特定资源所支持的HTTP请求方法.也可以利用向W ...

  4. Java 的 ArrayList 的底层数据结构

    1. 数据结构--ArrayList源码摘要 ublic class ArrayList<E> extends AbstractList<E> implements List& ...

  5. 使json或字典输出更美观

    这里是选取的项目中部分代码,但是关于json或字典格式化输出的代码是完整的def send_post(url, data): 使用json.dumps()后数据被转成了str类型,如果还要对该数据像字 ...

  6. make的使用和Makefile规则和编程及其基本命令(简单)

      转自:http://blog.chinaunix.net/uid-23929712-id-2650328.html   概述: make从Makefile中文件中获取模块间的依赖关系,判断哪些文件 ...

  7. mysql中not exists的简单理解

    http://www.cnblogs.com/glory-jzx/archive/2012/07/19/2599215.html http://sunxiaqw.blog.163.com/blog/s ...

  8. JS做深度学习2——导入训练模型

    JS做深度学习2--导入训练模型 改进项目 前段时间,我做了个RNN预测金融数据的毕业设计(华尔街),当时TensorFlow.js还没有发布,我不得已使用了keras对数据进行了训练,并且拟合好了不 ...

  9. Dockfile自动创建discuz论坛和可道云

    将discuz论坛的zip包解压之后用tar包压缩,这样ADD可以直接解压tar包. [root@localhost centos6.9_ssh_discuz]# pwd /opt/dockerfil ...

  10. 用Python拨打电话

    用python拨打电话,先看小视频 跟selenium操作浏览器原理类似,这是用appium操作移动设备的一个自动化功能,自娱自乐,主要是通过小案例引出相关技术 一.环境配置: 1.安装 jdk 1. ...