前文回顾

建议前一篇文章没看过的同学先看下前面的文章:

「老司机带你玩转面试(1):缓存中间件 Redis 基础知识以及数据持久化」

过期策略

Redis 的过期策略都有哪些?

在聊这个问题之前,一定要明确的一件事情是,如非必要,任何进入缓存的数据都应该设置过期时间,因为内存的大小是有限的,一台机器可能就那么几十个 G ,你不能拿内存和硬盘比,一台机器硬盘几个 T 都是洒洒水,只要想装,几十个 T 都装得下,关键还不贵。

Redis 设置删除策略,主要有两种思路,一种是定期删除,另一种是惰性删除。

定期删除:

设定一个时间,在 Redis 中默认是每隔 100ms 就随机抽取一些设置了过期时间的 key,检查其是否过期,如果过期就删除。

注意这里是随机抽取一些设置了过期时间的 key ,而是扫描所有,试想这样一个场景,如果我有 100w 个设置了过期时间的 key ,如果每次都全部扫描一遍,基本上 Redis 就死了, CPU 的负载会非常的高,全部都消耗在了检查过期 key 上面。

惰性删除:

惰性删除的意思就是当 key 过期后,不做删除动作,等到下次使用的时候,发现 key 已经过期,这时不在返回这个 key 对应的 value ,直接将这个 key 删除掉。

这种方式有一个致命的弱点,就是会有很多过期的 key-value 明明已经到了过期时间,缺还在内存中占着使用空间,大大降低了内存使用效率。

所以 Redis 的过期策略是:定期删除 + 惰性删除。

实际上简单的定期删除 + 惰性删除还是会存在问题,定期删除可能会导致很多过期 key 到了时间并没有被删除掉,然后我们也没有及时的去做检查,也没有做惰性删除,此时的结果就是大量过期 key 堆积在内存里,导致 Redis 的内存被耗尽。

咋整?答案是走内存淘汰机制。

内存淘汰机制都有哪些?

Redis 内存淘汰机制有以下几个:

  • noeviction: 当内存不足以容纳新写入数据时,新写入操作会报错。这个一般没啥人用吧,太傻了。
  • allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)。
  • allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个 key。这个一般没人用吧,为啥要随机,肯定是把最近最少使用的 key 给干掉啊。
  • volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的 key(这个一般不太合适)。
  • volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个 key。这个一般也没人用吧。
  • volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的 key 优先移除。

接下来,面试官就有可能要求手写一个 LRU 算法了,从头开始写确实有点困难,那代码量太大了,现场写也不大现实,但是借助 JDK 的现有的数据结构,写一个 LRU ,还是应该掌握下的,篇幅原因,我就不贴代码了,这一段代码一搜一大把,大家自己百度吧。

缓存雪崩、击穿、穿透

这几个问题也是在面试中经常会问到的,因为在实际的使用过程中,这一部分内容往往牵动了整个系统的安全性以及稳定性。

缓存雪崩

先了解下什么是缓存雪崩?

我先描述两个使用场景:

场景一:

线上正在运行的系统,突发状况, Redis 挂掉了,导致大量的数据访问不走 Redis ,直接落在了 DB 上,DB 扛不住这么大量的访问,直接崩掉了,这时如果 BD 是独立使用还好,如果不是独立的, DB 还和其他业务功能共享,那么势必会导致其他使用同一 DB 的业务功能一起崩掉,又会导致依赖于这些业务功能的其他系统接着完蛋,结果就是所有的系统和功能一起上天,这时,可能祭天一个程序员就不够了,整个 IT 部都要一起上天了。

场景二:

比如说电商平台,首页的热点数据都是放在缓存中的,早晨 8 点刷新了一批热点数据,设置有效期是 4 个小时,而在这 4 个小时中,并没有刷新新的热点数据,恰巧在中午 12 点的时候有一个秒杀活动。

悲惨的结果已经可以预见了,当时间走到 12 点,热点数据集体失效,而秒杀活动导致大量的用户疯狂的涌入,热点数据不存在,请求的数据直接落到了 DB 上,导致 DB 崩掉,重复一遍和场景一一样的惨况,整个 IT 部被拿来送上太阳,和我们的特朗普老师肩并肩。

上面两个场景的结果都是一样的,因为 Redis 的功能不可用,导致 BD 上天,从而导致 IT 部集体飞升。最坑的是这种事情发生后,还没有一个简单易行的处理方案,因为单纯的重启恢复服务这个套路已经不适用了,流量大的情况下,服务是起不来的好哇,服务刚起来就被流量干爬下,这种事情在国内某知名互联网公司发生过。只能是先在网关把所有流量拦截掉,然后恢复后端服务,并同步补充 Redis 的热 key ,等这些事情都 ok 以后,才能将流量放进来重新恢复服务,这么一套搞下来,几个小时没有了吧,当然,这个耗时视公司的不同而不同。

那么这种情况应该如何处理,先说说场景二,首先是不能使得所有的热点 key 同时失效,这里简单加一个随机数就好了,尤其是电商首页这种场景,直接设置热 key 永不失效都是可以的,要更新数据就直接更新,唯一的好处就是保险。

那么场景一这种情况我们还有什么解决方案呢?

首先,第一步要做到的就是 Redis 的高可用,随便什么方案,但绝对不能是单机,集群怎么也比单机挂掉的概率要小得多。

接下来,就是程序要启用本地 ehcache 缓存,还要加上服务限流与降级,服务限流降级前 Netflix 提供的 hystrix 后有 Alibaba 提供的 Sentinel ,选用什么看自己的使用场景,有了这个,至少保证了 BD 不会被一下打死,至少保证了服务的部分可用,哪怕只能保证 20% 的可用,对于用户来讲,就是多刷新几次页面的事情。

最后就是一定要开启 Redis 的持久化, Redis 一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。

缓存穿透

什么是缓存穿透?

还是讲一个场景,比如我的数据 id 是从 0 开始的自增序列,普通人请求没啥问题,每次都是用一个正常的 id 来进行访问,但是总有刁民搞事情,每次访问都使用 id 为 -1 来进行访问,因为 -1 并不存在,所有在 Redis 中也不会进行缓存,每次查询 DB 也查不到结果,这种请求直接无视了缓存的存在,直接作用于 DB ,只要访问量超过一定的数量,就会直接把数据库打死。

这种场景的解决方案其实很简单,比如我们可以在程序中对数据的合法性进行校验,如果数据不合法直接返回,比如上面的例子,如果 id 小于 0 ,直接返回失败。

但是单纯的这么操作并不能解决所有的问题,有时候我们并不好判断数据的合法性,就比如上面那个场景,比如数据中 id 最大只有 500 ,但是某些刁民老用一些大值进行请求,比如说 1000 ,这时虽然数据合法,但还是会落在 DB 上,这里我再提供一个简单粗暴的方式,当发现数据没查到数据的时候,在缓存中对这个 key 设置空的 value ,下次再进来就会去走缓存而不会落到 BD 上,这样也能有效防止缓存穿透。

缓存击穿

缓存击穿和雪崩是有点像的,雪崩是大批量的热 key 集体失效或者是不可用,导致请求直接落在 DB 上而打崩 DB ,最终导致整个系统的瘫痪。

而缓存击穿是指在某些情况下,会有一个极热极热的 key ,在扛着非常非常大的并发,突然过期失效,导致所有的请求在一瞬间落在了 DB 上,瞬间击垮 DB 导致全局崩盘。

看到这不知道大家想到了谁,反正我想到的是那个号称七星轨的软件,当然哈,人家的问题并不是缓存击穿,是真的扛不住,缓存直接被打崩了,毕竟我国的全民吃瓜,这个流量还是相当猛的。

都说到这了顺便聊聊它们的情况,第一次是不是缓存击穿现在已经无从考证了,基于这么多次的崩溃看下来,它们家的问题并不是软件层面的问题了,是硬件直接就不够,貌似每次解决问题都是直接联系阿里云扩容,阿里云容量一扩上去问题立马就没了。

你如果非要问硬件为什么不够,很简单么,那么多硬件不要钱啊,带宽不要钱的啊,你给啊,现在硬件带宽开那么高,又不是天天都有明星出轨我们都有瓜吃,空出来的浪费啊。

现在这种操作就挺好,平时硬件够用就行,明星出轨临时扩容,事件热点降低后再缩容回去,最近几次我看到扩容的速度明显快很多了,好几次从我知道崩了不能用到服务恢复只有不到半小时(也有可能是我消息闭塞),感觉阿里云的团队和某博的团队在经历了这么多大瓜以后已经能配合的非常默契了。

扯回来,我们接着说缓存击穿怎么处理。

不同场景下的解决方式如下:

  • 若缓存的数据是基本不会发生更新的,则可尝试将该热点数据设置为永不过期。
  • 若缓存的数据更新不频繁,且缓存刷新的整个流程耗时较少的情况下,则可以采用基于 Redis、zookeeper 等分布式中间件的分布式互斥锁,或者本地互斥锁以保证仅少量的请求能请求数据库并重新构建缓存,其余线程则在锁释放后能访问到新缓存。
  • 若缓存的数据更新频繁或者在缓存刷新的流程耗时较长的情况下,可以利用定时线程在缓存过期前主动地重新构建缓存或者延后缓存的过期时间,以保证所有的请求能一直访问到对应的缓存。

老司机带你玩转面试(2):Redis 过期策略以及缓存雪崩、击穿、穿透的更多相关文章

  1. 老司机带你玩转面试(3):Redis 高可用之主从模式

    前文回顾 建议前面文章没看过的同学先看下前面的文章: 「老司机带你玩转面试(1):缓存中间件 Redis 基础知识以及数据持久化」 「老司机带你玩转面试(2):Redis 过期策略以及缓存雪崩.击穿. ...

  2. 老司机带你玩转面试(4):Redis 高可用之哨兵模式

    前文回顾 建议前面文章没看过的同学先看下前面的文章: 「老司机带你玩转面试(1):缓存中间件 Redis 基础知识以及数据持久化」 「老司机带你玩转面试(2):Redis 过期策略以及缓存雪崩.击穿. ...

  3. 老司机带你玩转面试(5):Redis 集群模式 Redis Cluster

    前文回顾 建议前面文章没看过的同学先看下前面的文章: 「老司机带你玩转面试(1):缓存中间件 Redis 基础知识以及数据持久化」 「老司机带你玩转面试(2):Redis 过期策略以及缓存雪崩.击穿. ...

  4. 老司机带你玩转面试(1):缓存中间件 Redis 基础知识以及数据持久化

    引言 今天周末,我在家坐着掐指一算,马上又要到一年一度的金九银十招聘季了,国内今年上半年受到 YQ 冲击,金三银四泡汤了,这就直接导致很多今年毕业的同学会和明年毕业的同学一起参加今年下半年的秋招,这个 ...

  5. 编程老司机带你玩转 CompletableFuture 异步编程

    本文从实例出发,介绍 CompletableFuture 基本用法.不过讲的再多,不如亲自上手练习一下.所以建议各位小伙伴看完,上机练习一把,快速掌握 CompletableFuture. 个人博文地 ...

  6. 老司机带你玩转web service

    当大型需求被数个公司分割开来,各公司系统相互交换数据的问题就会接踵而来.毕竟是多家不同的公司的产品,研发开发语言.采用技术框架基本上是百花齐放.怎样让自家系统提供的服务具有跨平台.跨语言.跨各种防火墙 ...

  7. 老司机带你玩Spring.Net -入门篇

    网上有 Spring.Net 的相关的很多介绍的文章还有实践例子,推荐个还不错的博客 Spring.Net 学习笔记 .以前对 Spring.Net 算是有过一面之缘,但却迟迟未真正相识.在网上有太多 ...

  8. 老司机带你走进Core Animation

    为什么时隔这么久我又回来了呢? 回来圈粉. 开玩笑的,前段时间ipv6被拒啊,超级悲剧的,前后弄了好久,然后需求啊什么的又超多,所以写好的东西也没有时间整理.不过既然我现在回来了,那么这将是一个井喷的 ...

  9. 老司机带你开飞机 一: mssql on linux 安装指导

    通常在本机开发环境中需要搭建所有的服务,还要修改本地的hosts,实在是不胜其烦.如今有了docker,完全不用污染本地环境,且看老司机带你搭建一个asp.net core的开发环境集群.愿你走出虚拟 ...

随机推荐

  1. UDF_表值函数与标量函数的区别_分割字符串成单个的字符并返回表(插入到表中)

    UDF_区别_分割字符串成单个的字符并返回表(插入到表中) /* SQL表值函数和标量值函数的区别 实验环境:SQL Server 2014,参考maomao365有改编 在sqlserver中存储过 ...

  2. Git创建多个ssh key

    在使用git的时候,遇到需要创建多个ssh key的需求,一个用来git hub项目,一个用来git lab项目: 之前如果已将创建过一个ssh key,那么在创建第二个的时候,要修改默认名称,然后增 ...

  3. numpy中array数组对象的储存方式(n,1)和(n,)的区别

    资料:https://stackoverflow.com/questions/22053050/difference-between-numpy-array-shape-r-1-and-r 这篇文章是 ...

  4. C/S C# WPF锐浪报表教程

    前言:锐浪报表是一种中国式报表的报表开发工具.博主使用锐浪报表有一段时间了,积累了一些经验希望能帮助你快速掌握并使用 第一章:集成项目 首先我们先去锐浪报表官网下载并安装锐浪报表. 创建WPF应用程序 ...

  5. Beta冲刺<4/10>

    这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 Beta冲刺 这个作业的目标 Beta冲刺--第四天(05.22) 作业正文 如下 其他参考文献 ... B ...

  6. Beta冲刺<6/10>

    这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 Beta冲刺 这个作业的目标 Beta冲刺--第六天(05.24) 作业正文 如下 其他参考文献 ... B ...

  7. node+ajax实战案例(4)

    4.用户登录实现 4.1.用户登录实现思路 1 用户输入登录信息,点击登录的时候把用户登录的这些信息收集起来,然后组装数据通过ajax方式发送到后台 2 后台接到用户输入的登录信息,把这些信息拿去和数 ...

  8. 字节流,读取 a.txt 文件内容,并打印出来

    import java.io.FileInputStream;import java.io.IOException; /** 字节流,读取 a.txt 文件内容,并打印出来 */public clas ...

  9. 【MyBtis】获取数据插入postgresql后返回的自增id

    问题描述 数据库采用的是postgresql,以下面的rule表为例,该表的id设置为自增,那么经常有这样的需求,在执行insert操作后,紧接着需要获取该记录的自增id往中间表中插入数据,或者是再根 ...

  10. 如何解决TOP-K问题

    前言:最近在开发一个功能:动态展示的订单数量排名前10的城市,这是一个典型的Top-k问题,其中k=10,也就是说找到一个集合中的前10名.实际生活中Top-K的问题非常广泛,比如:微博热搜的前100 ...