Redis 缓存雪崩、击穿、穿透

Redis 缓存雪崩、击穿、穿透

文章目录

  • Redis 缓存雪崩、击穿、穿透
    • 一、Redis基础
      • Redis基本数据类型、操作
    • 二、面试相关问题
      • 1.小伙子您好,看你简历上写了你项目里面用到了Redis,你们为啥用Redis?
      • 2.那小伙子,我再问你,Redis有哪些数据结构呀?
      • 3.如果有大量的key需要设置同一时间过期,一般需要注意什么?
      • 4.那你使用过Redis分布式锁么,它是什么回事?
      • 5.这时候对方会告诉你说你回答得不错,然后接着问如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样?
      • 6.对方这时会显露笑容,心里开始默念:嗯,这小子还不错,开始有点意思了。假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如何将它们全部找出来?
      • 7.对方接着追问:如果这个redis正在给线上的业务提供服务,那使用keys指令会有什么问题?
      • 8.使用过Redis做异步队列么,你是怎么用的?
      • 9.如果对方追问可不可以不用sleep呢?
      • 10.如果对方接着追问能不能生产一次消费多次呢?
      • 11.如果对方继续追问 pub/su b有什么缺点?
      • 12.如果对方究极TM追问Redis如何实现延时队列?
      • 13.Redis是怎么持久化的?服务主从数据怎么交互的?
      • 14.对方追问那如果突然机器掉电会怎样?
      • 15.对方追问RDB的原理是什么?
      • 16.Pipeline有什么好处,为什么要用pipeline?
      • 17.Redis的同步机制了解么?
      • 18.是否使用过Redis集群,集群的高可用怎么保证,集群的原理是什么?
    • 三、Redis 缓存雪崩、击穿、穿透
      • 1.小伙子我看你的简历上写到了Redis,那么我们直接开门见山,直接怼常见的几个大问题,Redis雪崩了解么?
      • 2.面试官摸了摸自己的头发,嗯还不错,那这种情况咋整?你都是怎么去应对的?
      • 3.那你了解缓存穿透和击穿么,可以说说他们跟雪崩的区别么?
      • 4.面试官露出欣慰的眼光,那他们分别怎么解决
      • 5.那你还有别的办法么?
      • 6.总结

一、Redis基础

Redis基本数据类型、操作

Redis基本数据类型、操作详解:https://blog.csdn.net/wolfGuiDao/article/details/106432676

二、面试相关问题

1.小伙子您好,看你简历上写了你项目里面用到了Redis,你们为啥用Redis?

心里忍不住暗骂,这叫啥问题,大家不都是用的这个嘛,但是你不能说出来。

  • 认真回答道:帅气迷人的面试官您好,因为传统的关系型数据库如Mysql已经不能适用所有的场景了,比如秒杀的库存扣减,APP首页的访问流量高峰等等,都很容易把数据库打崩,所以引入了缓存中间件,目前市面上比较常用的缓存中间件有Redis和Memcached不过中和考虑了他们的优缺点,最后选择了Redis。

2.那小伙子,我再问你,Redis有哪些数据结构呀?

  • String、Hash、List、Set、SortedSet。

这里我相信99%的读者都能回答上来Redis的5个基本数据类型。如果回答不出来的小伙伴我们就要加油补课哟,大家知道五种类型最适合的场景更好。

  • 但是,如果你是Redis中高级用户,而且你要在这次面试中突出你和其他候选人的不同,还需要加上下面几种数据结构HyperLogLog、Geo、Pub/Sub
  • 如果你还想加分,那你说还玩过Redis Module,像BloomFilter,RedisSearch,Redis-ML,这个时候面试官得眼睛就开始发亮了,心想这个小伙子有点东西啊。

3.如果有大量的key需要设置同一时间过期,一般需要注意什么?

  • 如果大量的key过期时间设置的过于集中,到过期的那个时间点,Redis可能会出现短暂的卡顿现象。严重的话会出现缓存雪崩,我们一般需要在时间上加一个随机值,使得过期时间分散一些
  • 电商首页经常会使用定时任务刷新缓存,可能大量的数据失效时间都十分集中,如果失效时间一样,又刚好在失效的时间点大量用户涌入,就有可能造成缓存雪崩

4.那你使用过Redis分布式锁么,它是什么回事?

  • 先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。

5.这时候对方会告诉你说你回答得不错,然后接着问如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样?

  • 这时候你要给予惊讶的反馈:唉,是喔,这个锁就永远得不到释放了。紧接着你需要抓一抓自己得脑袋,故作思考片刻,好像接下来的结果是你主动思考出来的,然后回答:我记得set指令有非常复杂的参数,这个应该是可以同时把setnx和expire合成一条指令来用的

6.对方这时会显露笑容,心里开始默念:嗯,这小子还不错,开始有点意思了。假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如何将它们全部找出来?

  • 使用keys指令可以扫出指定模式的key列表。

7.对方接着追问:如果这个redis正在给线上的业务提供服务,那使用keys指令会有什么问题?

  • 这个时候你要回答Redis关键的一个特性:Redis的单线程的keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长
  • 不过,增量式迭代命令也不是没有缺点的:举个例子, 使用 SMEMBERS 命令可以返回集合键当前包含的所有元素, 但是对于SCAN 这类增量式迭代命令来说, 因为在对键进行增量式迭代的过程中, 键可能会被修改,所以增量式迭代命令只能对被返回的元素提供有限的保证

8.使用过Redis做异步队列么,你是怎么用的?

  • 一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试

9.如果对方追问可不可以不用sleep呢?

  • list还有个指令叫blpop,在没有消息的时候,它会阻塞住直到消息到来。

10.如果对方接着追问能不能生产一次消费多次呢?

  • 使用pub/sub主题订阅者模式,可以实现 1:N 的消息队列。

11.如果对方继续追问 pub/su b有什么缺点?

  • 在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如RocketMQ等。

12.如果对方究极TM追问Redis如何实现延时队列?

  • 这一套连招下来,我估计现在你很想把面试官一棒打死(面试官自己都想打死自己了怎么问了这么多自己都不知道的),如果你手上有一根棒球棍的话,但是你很克制。平复一下激动的内心,然后神态自若的回答道 使用sortedset,拿时间戳作为score,消息内容作为key调用zadd来生产消息,消费者用zrangebyscore指令获取N秒之前的数据轮询进行处理

到这里,面试官暗地里已经对你竖起了大拇指。并且已经默默给了你A+,但是他不知道的是此刻你却竖起了中指,在椅子背后。

13.Redis是怎么持久化的?服务主从数据怎么交互的?

  • RDB做镜像全量持久化,AOF做增量持久化。因为RDB会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据,所以需要AOF来配合使用。在redis实例重启时,会使用RDB持久化文件重新构建内存,再使用AOF重放近期的操作指令来实现完整恢复重启之前的状态。
  • 这里很好理解,把RDB理解为一整个表全量的数据,AOF理解为每次操作的日志就好了,服务器重启的时候先把表的数据全部搞进去,但是他可能不完整,你再回放一下日志,数据不就完整了嘛。
  • 不过Redis本身的机制是AOF持久化开启且存在AOF文件时,优先加载AOF文件;AOF关闭或者AOF文件不存在时,加载RDB文件;加载AOF/RDB文件城后,Redis启动成功;AOF/RDB文件存在错误时,Redis启动失败并打印错误信息

14.对方追问那如果突然机器掉电会怎样?

  • 取决于AOF日志sync属性的配置,如果不要求性能,在每条写指令时都sync一下磁盘,就不会丢失数据。但是在高性能的要求下每次都sync是不现实的,一般都使用定时sync,比如1s1次,这个时候最多就会丢失1s的数据

15.对方追问RDB的原理是什么?

  • 你给出两个词汇就可以了,fork和cow。fork是指redis通过创建子进程来进行RDB操作,cow指的是copy on write,子进程创建后,父子进程共享数据段,父进程继续提供读写服务,写脏的页面数据会逐渐和子进程分离开来

16.Pipeline有什么好处,为什么要用pipeline?

  • 可以将多次IO往返的时间缩减为一次,前提是pipeline执行的指令之间没有因果相关性。使用redis-benchmark进行压测的时候可以发现影响redis的QPS峰值的一个重要因素是pipeline批次指令的数目。

17.Redis的同步机制了解么?

  • Redis可以使用主从同步,从从同步。第一次同步时,主节点做一次bgsave,并同时将后续修改操作记录到内存buffer,待完成后将RDB文件全量同步到复制节点,复制节点接受完成后将RDB镜像加载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。后续的增量数据通过AOF日志同步即可,有点类似数据库的binlog

18.是否使用过Redis集群,集群的高可用怎么保证,集群的原理是什么?

  • Redis Sentinal 着眼于高可用,在master宕机时会自动将slave提升为master,继续提供服务。
  • Redis Cluster 着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。

面试结束

小伙子你可以的,什么时候有时间来上班啊,要不明天就来吧?

你强装镇定,这么急啊我还需要租房,要不下礼拜一吧。

好的 心想这小子这么NB是不是很多Offer在手上,不行我得叫hr给他加钱。

三、Redis 缓存雪崩、击穿、穿透

1.小伙子我看你的简历上写到了Redis,那么我们直接开门见山,直接怼常见的几个大问题,Redis雪崩了解么?

  • 帅气迷人的面试官您好,我了解的,目前电商首页以及热点数据都会去做缓存,一般缓存都是定时任务去刷新,或者是查不到之后去更新的,定时任务刷新就有一个问题。
  • 举个简单的例子:如果所有首页的Key失效时间都是12小时,中午12点刷新的,我零点有个秒杀活动大量用户涌入,假设当时每秒 6000个请求,本来缓存在可以扛住每秒 5000 个请求,但是缓存当时所有的Key都失效了
  • 此时 1 秒 6000 个请求全部落数据库,数据库必然扛不住,它会报一下警,真实情况可能DBA都没反应过来就直接挂了。
  • 此时,如果没用什么特别的方案来处理这个故障,DBA 很着急,重启数据库,但是数据库立马又被新的流量给打死了。这就是我理解的缓存雪崩。

感觉再吊的都不允许这么大的QPS直接打DB去,不过没慢SQL加上分库,大表分表可能还还算能顶,但是跟用了Redis的差距还是很大

Redis 缓存雪崩、击穿、穿透_第1张图片

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

2.面试官摸了摸自己的头发,嗯还不错,那这种情况咋整?你都是怎么去应对的?

  • 处理缓存雪崩简单,在批量往Redis存数据的时候,把每个Key的失效时间都加个随机值就好了,这样可以保证数据不会在同一时间大面积失效,我相信,Redis这点流量还是顶得住的。
setRedis(Key,value,time + Math.random() * 10000);
  • 如果Redis是集群部署,将热点数据均匀分布在不同的Redis库中也能避免全部失效的问题,不过本渣我在生产环境中操作集群的时候,单个服务都是对应的单个Redis分片,是为了方便数据的管理,但是也同样有了可能会失效这样的弊端,失效时间随机是个好策略。
  • 或者设置热点数据永远不过期,有更新操作就更新缓存就好了(比如运维更新了首页商品,那你刷下缓存就完事了,不要设置过期时间),电商首页的数据也可以用这个操作,保险。

3.那你了解缓存穿透和击穿么,可以说说他们跟雪崩的区别么?

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

小点的单机系统,基本上用postman就能搞死,比如我自己买的阿里云服务
Redis 缓存雪崩、击穿、穿透_第2张图片

  • 像这种你如果不对参数做校验,数据库id都是大于0的,我一直用小于0的参数去请求你,每次都能绕开Redis直接打到数据库,数据库也查不到,每次都这样,并发高点就容易崩掉了
  • 至于 缓存击穿 嘛,这个跟缓存雪崩有点像,但是又有一点不一样,缓存雪崩是因为大面积的缓存失效,打崩了DB
  • 而缓存击穿不同的是缓存击穿是指一个Key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个Key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个完好无损的桶上凿开了一个洞。
    Redis 缓存雪崩、击穿、穿透_第3张图片

4.面试官露出欣慰的眼光,那他们分别怎么解决

  • 缓存穿透我会在接口层增加校验,比如用户鉴权校验,参数做校验,不合法的参数直接代码Return,比如:id 做基础校验,id<=0的直接拦截等。
  • 这里我想提的一点就是,我们在开发程序的时候都要有一颗“不信任”的心,就是不要相信任何调用方,比如你提供了API接口出去,你有这几个参数,那我觉得作为被调用方,任何可能的参数情况都应该被考虑到,做校验,因为你不相信调用你的人,你不知道他会传什么参数给你
  • 举个简单的例子,你这个接口是分页查询的,但是你没对分页参数的大小做限制,调用的人万一一口气查 Integer.MAX_VALUE一次请求就要你几秒,多几个并发你不就挂了么?是公司同事调用还好大不了发现了改掉,但是如果是黑客或者竞争对手呢?在你双十一当天就调你这个接口会发生什么,就不用我说了吧。
  • 从缓存取不到的数据,在数据库中也没有取到,这时也可以将对应Key的Value对写为null、位置错误、稍后重试这样的值具体取啥问产品,或者看具体的场景,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。
  • 这样可以防止攻击用户反复用同一个id暴力攻击,但是我们要知道正常用户是不会在单秒内发起这么多次请求的,那网关层Nginx本渣我也记得有配置项,可以让运维大大对单个IP每秒访问次数超出阈值的IP都拉黑

5.那你还有别的办法么?

  • 还有我记得Redis还有一个高级用法布隆过滤器(Bloom Filter)这个也能很好的防止缓存穿透的发生,他的原理也很简单就是利用高效的数据结构和算法快速判断出你这个Key是否在数据库中存在,不存在你return就好了,存在你就去查了DB刷新KV再return
  • 那又有小伙伴说了如果黑客有很多个IP同时发起攻击呢?这点我一直也不是很想得通,但是一般级别的黑客没这么多肉鸡,再者正常级别的Redis集群都能抗住这种级别的访问的,小公司我想他们不会感兴趣的。把系统的高可用做好了,集群还是很能顶的。
  • 缓存击穿的话,设置热点数据永远不过期。或者加上互斥锁就能搞定了

作为暖男,代码我肯定帮你们准备好了
Redis 缓存雪崩、击穿、穿透_第4张图片

6.总结

  • 本文简单的介绍了,Redis的雪崩,击穿,穿透,三者其实都差不多,但是又有一些区别,在面试中其实这是问到缓存必问的,大家不要把三者搞混了,因为缓存雪崩、穿透和击穿,是缓存最大的问题,要么不出现,一旦出现就是致命性的问题,所以面试官一定会问你。
  • 大家一定要理解是怎么发生的,以及是怎么去避免的,发生之后又怎么去抢救,你可以不是知道很深入,但是你不能一点都不去想,面试有时候不一定是对知识面的拷问,或许是对你的态度的拷问,如果你思路清晰,然后知其然还知其所以然那就很赞,还知道怎么预防那来上班吧。
  • 最后暖男我继续给你们做个小的技术总结:
  • 一般避免以上情况发生我们从三个时间段去分析下:
  • 事前:Redis 高可用,主从+哨兵,Redis cluster,避免全盘崩溃。
  • 事中:本地 ehcache 缓存 + Hystrix 限流+降级,避免MySQL被打死。
  • 事后:Redis 持久化 RDB+AOF,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。
  • 限流组件,可以设置每秒的请求,有多少能通过组件,剩余的未通过的请求,怎么办?走降级!可以返回一些默认的值,或者友情提示,或者空白的值。
  • 好处:
  • 数据库绝对不会死,限流组件确保了每秒只有多少个请求能通过。只要数据库不死,就是说,对用户来说,3/5 的请求都是可以被处理的。只要有 3/5 的请求可以被处理,就意味着你的系统没死,对用户来说,可能就是点击几次刷不出来页面,但是多点几次,就可以刷出来一次
  • 这个在目前主流的互联网大厂里面是最常见的,你是不是好奇,某明星爆出什么事情,你发现你去微博怎么刷都空白界面,但是有的人又直接进了,你多刷几次也出来了,现在知道了吧,那是做了降级,牺牲部分用户的体验换来服务器的安全,可还行?

你可能感兴趣的:(数据库)