环球科创网

2022年01月03日整理发布:Redis的那些常见面试题总结附答案解析

更新时间:2022-01-03 15:42:48

导读 先来说说关于Redis常见面试问题的总结(附答案分析)。相信朋友们也应该很关心这个话题。现在,我们来为朋友们谈谈关于Redis的常见面试问题的

先来说说关于Redis常见面试问题的总结(附答案分析)。相信朋友们也应该很关心这个话题。现在,我们来为朋友们谈谈关于Redis的常见面试问题的总结(附答案分析)。边肖还收集了关于Redis常见采访问题的汇总相关信息(附答案分析)。我希望你看到后会喜欢。

遇到6大工厂,总结了Redis的常见问题(带答案分析),分享给大家。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。

【相关推荐:Redis视频教程】

缓存知识点

有哪些类型的缓存?

缓存是高并发场景下提高热数据访问性能的有效手段,常用于开发项目。

缓存有三种类型:本地缓存、分布式缓存和多级缓存。

本地缓存:

本地缓存意味着缓存在进程的内存中。例如,在我们的JVM堆中,我们可以使用LRUMap或像Ehcache这样的工具。

本地缓存是内存访问的最佳性能,没有远程交互的开销,但受单机容量限制,缓存一般较小,无法扩展。

分布式缓存:

分布式缓存可以很好地解决这个问题。

分布式缓存一般具有良好的横向扩展性,能够应对数据量较大的场景。缺点是远程请求的性能不如本地缓存。

多级缓存:

为了平衡这种情况,实际业务中一般采用多级缓存。本地缓存只保存一些访问频率最高的热数据,其他热数据放在分布式缓存中。

目前这也是一线厂商最常用的缓存方案。单个缓存方案通常很难支持许多高并发场景。

消除策略

为了确保高性能,本地缓存和分布式缓存都使用内存来存储数据。由于成本和内存限制,当存储的数据超过缓存容量时,需要消除缓存的数据。

一般剔除策略包括先进先出剔除最早的数据,LRU剔除最近最少使用的数据,LFU剔除最近最少使用的数据。

当达到内存限制并且客户端尝试执行将会使用更多内存的命令时(大多数写命令,但是DEL和少数例外),Noeviction:返回错误。

Allkeys-lru:尝试回收最少使用的密钥(lru),为新添加的数据腾出空间。

Volatile-lru:尝试回收最少使用的密钥(lru),但只回收过期集中的密钥,以便为新添加的数据留出空间。

Allkeys-random:回收随机密钥,以便为新添加的数据留出空间。

Volatile-random:回收随机密钥,这使得新添加的数据有存储空间,但只能存储过期集中的密钥。

Volatile-ttl:回收过期集合中的密钥,优先回收ttl较短的密钥,这样就有空间存放新添加的数据。

如果没有一个密钥满足回收的前提条件,那么volatile-lru、volatile-random和volatile-ttl策略与noeviction类似。

事实上,Lru算法也在熟悉的LinkedHashMap中实现,如下所示:

当容量超过100时,将实施LRU策略:将驱逐最近最少使用的TimeoutInfoHolder对象。

在真实的面试中,会要求你写LUR算法。不要搞原创的,写起来真的太多了。你可以从上面一个学习,也可以从下面一个学习。更容易找到一个数据结构来实现Java版本的LRU。只要知道原理就行了。

Memcache

请注意,Memcache稍后将缩写为MC。

我们先来看看MC的特点:

MC采用多线程异步IO处理请求,可以合理利用CPU多核的优势。表演非常精彩。MC功能简单,使用内存存储数据;MC的记忆结构和钙化我就不细说了。你可以查看官网了解一下。MC可以为缓存的数据设置到期期限,到期后数据将被清除;失效策略采用延迟失效,即当数据再次使用时,检查是否无效;当容量已满时,缓存中的数据将被拒绝。除了清除过期密钥之外,根据LRU政策,数据将被拒绝。此外,使用MC还有一些限制。这些限制在目前的互联网场景下是致命的,这也成为人们选择Redis和MongoDB的重要原因:

密钥不能超过250字节;该值不能超过1M个字。

节;key 的最大失效时间是 30 天;只支持 K-V 结构不提供持久化和主从同步功能。

Redis

先简单说一下 Redis 的特点方便和 MC 比较。

与 MC 不同的是Redis 采用单线程模式处理请求。这样做的原因有 2 个:一个是因为采用了非阻塞的异步事件处理机制;另一个是缓存数据都是内存操作 IO 时间不会太长单线程可以避免线程上下文切换产生的代价。Redis 支持持久化所以 Redis 不仅仅可以用作缓存也可以用作 NoSQL 数据库。相比 MCRedis 还有一个非常大的优势就是除了 K-V 之外还支持多种数据格式例如 list、set、sorted set、hash 等。Redis 提供主从同步机制以及 Cluster 集群部署能力能够提供高可用服务。

详解 Redis

Redis 的知识点结构如下图所示。

功能

来看 Redis 提供的功能有哪些吧!

我们先看基础类型:

String:

String 类型是 Redis 中最常使用的类型内部的实现是通过 SDS(Simple Dynamic String )来存储的。SDS 类似于 Java 中的 ArrayList可以通过预分配冗余空间的方式来减少内存的频繁分配。

这是最简单的类型就是普通的 set 和 get做简单的 KV 缓存。

但是真实的开发环境中很多仔可能会把很多比较复杂的结构也统一转成String去存储使用比如有的仔他就喜欢把对象或者List转换为JSONString进行存储拿出来再反序列话啥的。

我在这里就不讨论这样做的对错了但是我还是希望大家能在最合适的场景使用最合适的数据结构对象找不到最合适的但是类型可以选最合适的嘛之后别人接手你的代码一看这么规范诶这小伙子有点东西呀看到你啥都是用的String垃圾!

好了这些都是题外话了道理还是希望大家记在心里习惯成自然嘛小习惯成就你。

String的实际应用场景比较广泛的有:

缓存功能:String字符串是最常用的数据类型不仅仅是Redis各个语言都是最基本类型因此利用Redis作为缓存配合其它数据库作为存储层利用Redis支持高并发的特点可以大大加快系统的读写速度、以及降低后端数据库的压力。

计数器:许多系统都会使用Redis作为系统的实时计数器可以快速实现计数和查询的功能。而且最终的数据结果可以按照特定的时间落地到数据库或者其它存储介质当中进行永久保存。

共享用户Session:用户重新刷新一次界面可能需要访问一下数据进行重新登录或者访问页面缓存Cookie但是可以利用Redis将用户的Session集中管理在这种模式只需要保证Redis的高可用每次用户Session的更新和获取都可以快速完成。大大提高效率。

Hash:

这个是类似 Map 的一种结构这个一般就是可以将结构化的数据比如一个对象(前提是这个对象没嵌套其他的对象)给缓存在 Redis 里然后每次读写缓存的时候可以就操作 Hash 里的某个字段。

但是这个的场景其实还是多少单一了一些因为现在很多对象都是比较复杂的比如你的商品对象可能里面就包含了很多属性其中也有对象。我自己使用的场景用得不是那么多。

List:

List 是有序列表这个还是可以玩儿出很多花样的。

比如可以通过 List 存储一些列表型的数据结构类似粉丝列表、文章的评论列表之类的东西。

比如可以通过 lrange 命令读取某个闭区间内的元素可以基于 List 实现分页查询这个是很棒的一个功能基于 Redis 实现简单的高性能分页可以做类似微博那种下拉不断分页的东西性能高就一页一页走。

比如可以搞个简单的消息队列从 List 头怼进去从 List 屁股那里弄出来。

List本身就是我们在开发过程中比较常用的数据结构了热点数据更不用说了。

消息队列:Redis的链表结构可以轻松实现阻塞队列可以使用左进右出的命令组成来完成队列的设计。比如:数据的生产者可以通过Lpush命令从左边插入数据多个数据消费者可以使用BRpop命令阻塞的“抢”列表尾部的数据。

文章列表或者数据分页展示的应用。

比如我们常用的博客网站的文章列表当用户量越来越多时而且每一个用户都有自己的文章列表而且当文章多时都需要分页展示这时可以考虑使用Redis的列表列表不但有序同时还支持按照范围内获取元素可以完美解决分页查询功能。大大提高查询效率。

Set:

Set 是无序集合会自动去重的那种。

直接基于 Set 将系统里需要去重的数据扔进去自动就给去重了如果你需要对一些数据进行快速的全局去重你当然也可以基于 JVM 内存里的 HashSet 进行去重但是如果你的某个系统部署在多台机器上呢得基于Redis进行全局的 Set 去重。

可以基于 Set 玩儿交集、并集、差集的操作比如交集吧我们可以把两个人的好友列表整一个交集看看俩人的共同好友是谁对吧。

反正这些场景比较多因为对比很快操作也简单两个查询一个Set搞定。

Sorted Set:

Sorted set 是排序的 Set去重但可以排序写进去的时候给一个分数自动根据分数排序。

有序集合的使用场景与集合类似但是set集合不是自动有序的而Sorted set可以利用分数进行成员间的排序而且是插入时就排序好。所以当你需要一个有序且不重复的集合列表时就可以选择Sorted set数据结构作为选择方案。

排行榜:有序集合经典使用场景。例如视频网站需要对用户上传的视频做排行榜榜单维护可能是多方面:按照时间、按照播放量、按照获得的赞数等。

用Sorted Sets来做带权重的队列比如普通消息的score为1重要消息的score为2然后工作线程可以选择按score的倒序来获取工作任务。让重要的任务优先执行。

微博热搜榜就是有个后面的热度值前面就是名称

高级用法:

Bitmap :

位图是支持按 bit 位来存储信息可以用来实现 布隆过滤器(BloomFilter);

HyperLogLog:

供不精确的去重计数功能比较适合用来做大规模数据的去重统计例如统计 UV;

Geospatial:

可以用来保存地理位置并作位置距离计算或者根据半径计算位置等。有没有想过用Redis来实现附近的人或者计算最优地图路径

这三个其实也可以算作一种数据结构不知道还有多少朋友记得我在梦开始的地方Redis基础中提到过你如果只知道五种基础类型那只能拿60分如果你能讲出高级用法那就觉得你有点东西。

pub/sub:

功能是订阅发布功能可以用作简单的消息队列。

Pipeline:

可以批量执行一组指令一次性返回全部结果可以减少频繁的请求应答。

Lua:

Redis 支持提交 Lua 脚本来执行一系列的功能。

我在前电商老东家的时候秒杀场景经常使用这个东西讲道理有点香利用他的原子性。

话说你们想看秒杀的设计么我记得我面试好像每次都问啊想看的直接点赞后评论秒杀吧。

事务:

最后一个功能是事务但 Redis 提供的不是严格的事务Redis 只保证串行执行命令并且能保证全部执行但是执行命令失败时并不会回滚而是会继续执行下去。

持久化

Redis 提供了 RDB 和 AOF 两种持久化方式RDB 是把内存中的数据集以快照形式写入磁盘实际操作是通过 fork 子进程执行采用二进制压缩存储;AOF 是以文本日志的形式记录 Redis 处理的每一个写入或删除操作。

RDB 把整个 Redis 的数据保存在单一文件中比较适合用来做灾备但缺点是快照保存完成之前如果宕机这段时间的数据将会丢失另外保存快照时可能导致服务短时间不可用。

AOF 对日志文件的写入操作使用的追加模式有灵活的同步策略支持每秒同步、每次修改同步和不同步缺点就是相同规模的数据集AOF 要大于 RDBAOF 在运行效率上往往会慢于 RDB。

细节的点大家去高可用这章看特别是两者的优缺点以及怎么抉择。

《吊打面试官》系列-Redis哨兵、持久化、主从、手撕LRU

高可用

来看 Redis 的高可用。Redis 支持主从同步提供 Cluster 集群部署模式通过 Sentine l哨兵来监控 Redis 主服务器的状态。当主挂掉时在从节点中根据一定策略选出新主并调整其他从 slaveof 到新主。

选主的策略简单来说有三个:

slave 的 priority 设置的越低优先级越高;同等情况下slave 复制的数据越多优先级越高;相同的条件下 runid 越小越容易被选中。

在 Redis 集群中sentinel 也会进行多实例部署sentinel 之间通过 Raft 协议来保证自身的高可用。

Redis Cluster 使用分片机制在内部分为 16384 个 slot 插槽分布在所有 master 节点上每个 master 节点负责一部分 slot。数据操作时按 key 做 CRC16 来计算在哪个 slot由哪个 master 进行处理。数据的冗余是通过 slave 节点来保障。

哨兵

哨兵必须用三个实例去保证自己的健壮性的哨兵+主从并不能保证数据不丢失但是可以保证集群的高可用。

为啥必须要三个实例呢我们先看看两个哨兵会咋样。

master宕机了 s1和s2两个哨兵只要有一个认为你宕机了就切换了并且会选举出一个哨兵去执行故障但是这个时候也需要大多数哨兵都是运行的。

那这样有啥问题呢M1宕机了S1没挂那其实是OK的但是整个机器都挂了呢哨兵就只剩下S2个裸屌了没有哨兵去允许故障转移了虽然另外一个机器上还有R1但是故障转移就是不执行。

经典的哨兵集群是这样的:

M1所在的机器挂了哨兵还有两个两个人一看他不是挂了嘛那我们就选举一个出来执行故障转移不就好了。

暖男我小的总结下哨兵组件的主要功能:

集群监控:负责监控 Redis master 和 slave 进程是否正常工作。消息通知:如果某个 Redis 实例有故障那么哨兵负责发送消息作为报警通知给管理员。故障转移:如果 master node 挂掉了会自动转移到 slave node 上。配置中心:如果故障转移发生了通知 client 客户端新的 master 地址。

主从

提到这个就跟我前面提到的数据持久化的RDB和AOF有着比密切的关系了。

我先说下为啥要用主从这样的架构模式前面提到了单机QPS是有上限的而且Redis的特性就是必须支撑读高并发的那你一台机器又读又写这谁顶得住啊不当人啊!但是你让这个master机器去写数据同步给别的slave机器他们都拿去读分发掉大量的请求那是不是好很多而且扩容的时候还可以轻松实现水平扩容。

你启动一台slave 的时候他会发送一个psync命令给master 如果是这个slave第一次连接到master他会触发一个全量复制。master就会启动一个线程生成RDB快照还会把新的写请求都缓存在内存中RDB文件生成后master会将这个RDB发送给slave的slave拿到之后做的第一件事情就是写进本地的磁盘然后加载进内存然后master会把内存里面缓存的那些新命名都发给slave。

我发出来之后来自CSDN的网友:Jian_Shen_Zer 问了个问题:

主从同步的时候新的slaver进来的时候用RDB那之后的数据呢有新的数据进入master怎么同步到slaver啊

敖丙答:笨AOF嘛增量的就像MySQL的Binlog一样把日志增量同步给从服务就好了

key 失效机制

Redis 的 key 可以设置过期时间过期后 Redis 采用主动和被动结合的失效机制一个是和 MC 一样在访问时触发被动删除另一种是定期的主动删除。

定期+惰性+内存淘汰

缓存常见问题

缓存更新方式

这是决定在使用缓存时就该考虑的问题。

缓存的数据在数据源发生变更时需要对缓存进行更新数据源可能是 DB也可能是远程服务。更新的方式可以是主动更新。数据源是 DB 时可以在更新完 DB 后就直接更新缓存。

当数据源不是 DB 而是其他远程服务可能无法及时主动感知数据变更这种情况下一般会选择对缓存数据设置失效期也就是数据不一致的最大容忍时间。

这种场景下可以选择失效更新key 不存在或失效时先请求数据源获取最新数据然后再次缓存并更新失效期。

但这样做有个问题如果依赖的远程服务在更新时出现异常则会导致数据不可用。改进的办法是异步更新就是当失效时先不清除数据继续使用旧的数据然后由异步线程去执行更新任务。这样就避免了失效瞬间的空窗期。另外还有一种纯异步更新方式定时对数据进行分批更新。实际使用时可以根据业务场景选择更新方式。

数据不一致

第二个问题是数据不一致的问题可以说只要使用缓存就要考虑如何面对这个问题。缓存不一致产生的原因一般是主动更新失败例如更新 DB 后更新 Redis 因为网络原因请求超时;或者是异步更新失败导致。

解决的办法是如果服务对耗时不是特别敏感可以增加重试;如果服务对耗时敏感可以通过异步补偿任务来处理失败的更新或者短期的数据不一致不会影响业务那么只要下次更新时可以成功能保证最终一致性就可以。

缓存穿透

缓存穿透。产生这个问题的原因可能是外部的恶意攻击例如对用户信息进行了缓存但恶意攻击者使用不存在的用户id频繁请求接口导致查询缓存不命中然后穿透 DB 查询依然不命中。这时会有大量请求穿透缓存访问到 DB。

解决的办法如下。

对不存在的用户在缓存中保存一个空对象进行标记防止相同 ID 再次访问 DB。不过有时这个方法并不能很好解决问题可能导致缓存中存储大量无用数据。

使用 BloomFilter 过滤器BloomFilter 的特点是存在性检测如果 BloomFilter 中不存在那么数据一定不存在;如果 BloomFilter 中存在实际数据也有可能会不存在。非常适合解决这类的问题。

缓存击穿

缓存击穿就是某个热点数据失效时大量针对这个数据的请求会穿透到数据源。

解决这个问题有如下办法。

可以使用互斥锁更新保证同一个进程中针对同一个数据不会并发请求到 DB减小 DB 压力。

使用随机退避方式失效时随机 sleep 一个很短的时间再次查询如果失败再执行更新。

针对多个热点 key 同时失效的问题可以在缓存时使用固定时间加上一个小的随机数避免大量热点 key 同一时刻失效。

缓存雪崩

缓存雪崩产生的原因是缓存挂掉这时所有的请求都会穿透到 DB。

解决方法:

使用快速失败的熔断策略减少 DB 瞬间压力;

使用主从模式和集群模式来尽量保证缓存服务的高可用。

实际场景中这两种方法会结合使用。

老朋友都知道为啥我没有大篇幅介绍这个几个点了吧我在之前的文章实在是写得太详细了忍不住点赞那种我这里就不做重复拷贝了。

《吊打面试官》系列-Redis基础《吊打面试官》系列-缓存雪崩、击穿、穿透《吊打面试官》系列-Redis哨兵、持久化、主从、手撕LRU《吊打面试官》系列-Redis终章-凛冬将至、FPX-新王登基

考点与加分项

拿笔记一下!

考点

面试的时候问你缓存主要是考察缓存特性的理解对 MC、Redis 的特点和使用方式的掌握。

要知道缓存的使用场景不同类型缓存的使用方式例如:

- 对 DB 热点数据进行缓存减少 DB 压力;对依赖的服务进行缓存提高并发性能;

- 单纯 K-V 缓存的场景可以使用 MC而需要缓存 list、set 等特殊数据格式可以使用 Redis;

- 需要缓存一个用户最近播放视频的列表可以使用 Redis 的 list 来保存、需要计算排行榜数据时可以使用 Redis 的 zset 结构来保存。

要了解 MC 和 Redis 的常用命令例如原子增减、对不同数据结构进行操作的命令等。

了解 MC 和 Redis 在内存中的存储结构这对评估使用容量会很有帮助。

了解 MC 和 Redis 的数据失效方式和剔除策略比如主动触发的定期剔除和被动触发延期剔除

要理解 Redis 的持久化、主从同步与 Cluster 部署的原理比如 RDB 和 AOF 的实现方式与区别。

要知道缓存穿透、击穿、雪崩分别的异同点以及解决方案。

不管你有没有电商经验我觉得你都应该知道秒杀的具体实现以及细节点。

……..

加分项

如果想要在面试中获得更好的表现还应了解下面这些加分项。

是要结合实际应用场景来介绍缓存的使用。例如调用后端服务接口获取信息时可以使用本地+远程的多级缓存;对于动态排行榜类的场景可以考虑通过 Redis 的 Sorted set 来实现等等。

最好你有过分布式缓存设计和使用经验例如项目中在什么场景使用过 Redis使用了什么数据结构解决哪类的问题;使用 MC 时根据预估值大小调整 McSlab 分配参数等等。

最好可以了解缓存使用中可能产生的问题。比如 Redis 是单线程处理请求应尽量避免耗时较高的单个请求任务防止相互影响;Redis 服务应避免和其他 CPU 密集型的进程部署在同一机器;或者禁用 Swap 内存交换防止 Redis 的缓存数据交换到硬盘上影响性能。再比如前面提到的 MC 钙化问题等等。

要了解 Redis 的典型应用场景例如使用 Redis 来实现分布式锁;使用 Bitmap 来实现 BloomFilter使用 HyperLogLog 来进行 UV 统计等等。

知道 Redis4.0、5.0 中的新特性例如支持多播的可持久化消息队列 Stream;通过 Module 系统来进行定制功能扩展等等。

……..

更多编程相关知识请访问:编程视频!!

以上就是Redis的那些常见面试题总结(附答案解析)的详细内容!

来源:php中文网

免责声明:本文由用户上传,如有侵权请联系删除!