首页 > 编程知识 正文

redis缓存面试题(redis热点key解决方案)

时间:2023-05-04 19:23:05 阅读:84826 作者:2100

过期策略

Redis 的过期策略都有哪些?

在谈这个问题之前,一定要弄清楚一些事情。 如果不需要,必须为进入缓存的数据设置有效期限。 由于内存大小有限,一台机器可能会变成几十个g。 不能比较内存和硬盘。 一台机器的硬盘上溅了好几吨水。 如果想装的话,可以装几十个t。 重要的是还不高。

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

定期删除:

设定时间,Redis随机抽取默认每100ms设定一次有效期限的密钥,检查是否过期,如果过期则删除。

请注意,这里不是随机提取已过期的密钥,而是扫描所有密钥。 想想这样的场景。 即使我有100w个设定了有效期限的密钥,如果每次都扫描的话,基本上Redis就会死,CPU的负荷会变得非常高,全部都会被用于有效期限的检查。

惰性删除:

惯性删除是指,在密钥过期后,不进行删除动作,在下次使用时,如果发现密钥已经过期,则不返回到与该密钥对应的值,而是直接删除密钥。

这种方式有致命的弱点。 过期的密钥值已经过期,但缺少的空间却占用了内存中的空间,这大大降低了内存的使用效率。

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

事实上,简单的定期惰性删除还存在问题。 定期删除可能会导致许多过期密钥到时间也不会被删除。 之后,我们没有马上检查,也没有进行惰性删除。 结果,大量过期的密钥会累积在内存中,从而导致Redis内存耗尽。

怎么做? 答案是走内存淘汰机制。

内存淘汰机制都有哪些?

Redis内存的废弃机制如下。

如果 noeviction:内存不足以向lqdz写入数据,则新的写入操作会发生错误。 这个一般谁也不用吧。 我是笨蛋。

allkeys-lru :如果内存不足以向lqdz写入数据,请从密钥空间中删除最近最不使用的密钥。 这是最常见的。

allkeys-random :内存不足以用lqdz写入数据时,从密钥空间随机删除某个密钥。 这个一般谁也不用吧。 为什么要随机呢? 一定会杀了最近最不用的key啊。

如果没有足够的内存写入volatile-LRU:lqdz,请从设置了过期日期的密钥空间中删除最近使用的密钥(这通常不太合适)。

volatile-random (如果没有足够的内存写入lqdz,在设置了有效期限的密钥区域中随机删除某个密钥。 这个一般也不会有人用吧。

volatile-ttl :如果内存不足以写入lqdz,则具有较旧过期日期的密钥区域将被优先删除。

其次,面试官可能要求手写LRU算法。 从一开始写确实有点困难。 那个代码量太大了,在现场写也不现实。 但是,利用JDK现有的数据结构,写LRU还是应该把握的。 因为篇幅的原因,我不贴代码。 这个代码一个一个检索,大家自己百度写吧。

缓存雪崩、击穿、穿透

这个问题在面试中也经常被问到。 因为在实际使用过程中,这部分往往会带动整个系统的安全性和稳定性。

缓存雪崩

缓存雪崩是什么?

首先说明两个使用场景。

场景1 :

在线运行的系统由于突发情况下Redis锁定,大量数据访问不通过Redis,直接落入数据库。 DB承担不了这么大量的访问,就这样崩溃了。 此时,如果BD被独立使用还说得过去,如果不独立,则DB会与其他业务功能共享,和使用同一DB的其他业务功能一起崩溃。 此外,依赖于这些业务功能的其他系统将结束,结果将是所有系统和功能一起上天。 这个时候,程序员一个人可能不够了,整个IT部可能会一起上天。

场景2 :

例如,在EC平台上,首页的所有热点数据都存储在缓存中。 早上8点更新热点数据,有效期为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 等分布式中间件的分布式互斥锁,或者本地互斥锁以保证仅少量的请求能请求数据库并重新构建缓存,其余线程则在锁释放后能访问到新缓存。

· 若缓存的数据更新频繁或者在缓存刷新的流程耗时较长的情况下,可以利用定时线程在缓存过期前主动地重新构建缓存或者延后缓存的过期时间,以保证所有的请求能一直访问到对应的缓存

来源:https://juejin.im/post/6850418114107179022

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。