大厂面试---Redis面试题(含答案,相关知识点,面试考察次数统计)_安吉_lh1029的博客-CSDN博客
大厂面试问答题汇总分析---数据库(索引-聚集/非聚集,事务,mySql, 锁)_安吉_lh1029的博客-CSDN博客
大厂面试问答题汇总分析---网络安全类问题_安吉_lh1029的博客-CSDN博客
大厂面试问答题汇总分析--- 秒杀 / 限流 / 高并发_安吉_lh1029的博客-CSDN博客
【锁】的相关概念汇总_安吉_lh1029的博客-CSDN博客
大厂面试问答题汇总分析--- 多线程问题_安吉_lh1029的博客-CSDN博客
概述摘要:
Redis(本质是内存数据库),【数据库】相关题目在历届大厂面试中占比20%到30%之间 【根据600多道大厂面试题】,有的公司该类题目占比比例会更高。本文梳理就是针对高频题目和相关知识点的梳理学习,包含高频问题和相关所有答案。
面试题目考察频次列表(仅以本次大厂面经提供题目,进行归纳分析,作为样本)
| 【超高频】 | 考察次数 > 5 |
| 【高频】 | 5 >= 考察次数 > 3 |
| 【中频】 | 3 >= 考察次数 > 1 |
| 【普通】 | 考察次数 = 1 |
3、【超高频】Redis数据类型有哪些?对应使用场景?其中zSet的底层实现
----- zSet 相关问题: zSet的底层结构是什么?zSet为什么用跳表实现?为什么不用红黑树?
4、【超高频】Reids如何持久化?有哪些持久化方式,优缺点是什么?
分布式锁实现比较【数据库】【Zookeeper】【Redis】
8、【高频】Reids的集群架构方案?master-slave模式,以及哨兵模式
9-1 三种过期删除的策略比较(定时删除、惰性删除、定期删除)
题目答案和相关知识点解析
1、【中频】Redis 网络模型是什么?
Redis 就是一个高性能的数据库, Redis 的数据是存在内存中的,所以读写速度非常快,因此 Redis 被广泛应用于缓存方向。Redis 与其他 key - value 缓存产品有以下三个特点:
- 支持数据的持久化,可将内存中的数据保存在磁盘中,重启时再次加载进行使用。
- 不仅支持简单的key-value类型的数据,还提供list,set,zset,hash等数据结构的存储。
- 支持数据的备份,即master-slave模式的数据备份
2、【普通】Redis在项目中都使用了哪些功能?
Redis 被广泛应用于缓存方向。另外,Redis 也经常用来做分布式锁。Redis 提供了多种数据类型来支持不同的业务场景。除此之外,Redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。
- 会话缓存(最常用)
- 消息队列(支付)
- 活动排行榜或计数
- 发布,订阅消息(消息通知)
- 商品列表,评论列表
(可详看问题3中不同数据类型 支持 使用场景, 这种题一般结合其他知识点问,单独问的比较少,一般问Reids如何实现分布式锁? 如何避免Redis缓存穿透? 等)
3、【超高频】Redis数据类型有哪些?对应使用场景?其中zSet的底层实现
| 支持的 数据类型 | 存储结构 | 内部编码模式 | 使用 场景 |
| 1--String (字符串) | JSON、XML, 二进制的图片等,但不能超过512MB | int:8个字节长整型 embstr:<=39个字节的字符串 raw:>39个字节的字符串 | 缓存, 计数 共享Session 限速 |
| 2--Hash (字典) | 键值对 | ziplist(压缩列表):个数小于512个(默认)且所有值小于64字节(默认) hashtable (哈希表):其余情况 | 存储、读取、修改用户属性 |
| 3--List (列表) | 多个有序的字符串, 最多可以存储2^32-1个元素 | ziplist(压缩列表):同上 linkedlist(链表):其余情况 | 最新消息排行等功能(如朋友圈的时间线);消息队列 栈, 文章列表 |
| 4--Set (集合) | 多个字符串元素, 不允许重复且无序 | intset(整数集合):都是整数且个数小于512个(默认) hashtable(哈希表):其余情况 | 用户标签, 抽奖功能 |
| 【超高频】 5--zSet、(有序集合) | 不允许重复且可排序,每个元素设置score作排序依据 | ziplist(压缩列表):有序个数小于128个(默认) 且所有值小于64字节(默认) skiplist(跳跃表):其余情况 | 排行榜 延迟消息队列 |
----- zSet 相关问题: zSet的底层结构是什么?zSet为什么用跳表实现?为什么不用红黑树?
【超高频】zSet的底层结构是什么?(或问排序原理/ 实现)答:是跳表
【中频】zSet为什么用跳表实现?为什么不用红黑树?两者对比
答:skiplist(跳表)1)是一种多层的有序链表
2)跳表查询:每在上层搜索一次就平均缩小了一半的搜索范围,平均时间复杂度为O(logn)
3)与【红黑树】比较:
| 跳表 | 红黑树 | ||
| 相同点 | 查询/插入/删除 复杂度两者相同,都为O(logn) | ||
| 不同点 | 1、插入/删除 | 插入相邻节点 | 操作后需要调整 |
| 2、范围查询 | 更适合范围查询,找到范围最小值,在第一层遍历即可 | 效率没有跳表高 | |
| 3、实现 | 更为简单 | 相对复杂 | |
【普通】redis的数据结构,对长字符串和短字符串处理有什么不同?
答:Redis 会根据当前值的 类型 和 长度 决定使用哪种 内部编码实现。短字符串使用embstr(<=39个字节的字符串),长字符串使用raw(39个字节的字符串)[引申就是SDS相关,有兴趣可参考文档:Redis开发与运维:SDS与embstr、raw 深入理解]
4、【超高频】Reids如何持久化?有哪些持久化方式,优缺点是什么?
| 持久化方式 | RDB | AOF |
| 全称 | Redis database | append only file |
| 持久化过程 | 1.在生成快照时,将当前进程fork出一个子进程. 2.子进程中循环所有的数据,将数据写入到二进制文件 3.当子进程将【快照Snapshot】写入临时文件完毕后,用临时文件替换原来的快照文件,然后子进程退出。 | 采用日志的形式来记录每个写操作,并追加到文件中 |
| 优点 | 1-方便备份 2-易移动到其他存储物质 3-最大化redis性能,父进程无需额外I/O操作 | 数据的完整性和一致性更高 |
| 缺点 | 1、定时存储,定时间故障停机损失数据,完整一致性较差 2-数据集庞大时,Fork非常耗时,影响服务器处理客户端 | AOF记录的内容多,文件会越来越大,数据恢复也会越来越慢 |
综上:
1)AOF方式,Redis默认不开启。它的出现是为了弥补RDB的不足(数据的不一致性)
2)两种方式【同时开启】,数据恢复【优先选择】AOF恢复
3)默认,开启【RDB】模式, 【AOF】需手动开启
4)只打算用【Redis做缓存】,可以【关闭持久化】,使用Redis的持久化。建议RDB和AOF【都开启】
备注:针对AOF文件大的问题,Redis提供重写的瘦身机制
5、【中频】如何避免Redis缓存穿透?存在哪些缓存问题?
| 缓存穿透 | 含义 | 是指查询一个数据库一定不存在的数据 |
| 危害 | 恶意攻击|利用这个漏洞,对数据库造成压力,压垮数据库 | |
| 解决 | 1、布隆过滤器,将数据库中的所有key都存储在布隆过滤器中,在查询Redis前先去布隆过滤器查询 key 是否存在,如果不存在就直接返回,不让其访问数据库,从而避免了对底层存储系统的查询压力。(一定不存在的数据会被这个bitmap拦截掉) 针对这种key异常多、请求重复率比较低的数据用【布隆过滤器】 2、粗暴法:将无效的key存放进Redis中,直接设置value=“null”存放到缓存,过期时间设置很短 (局限性:假如传进来的这个不存在的Key值每次都是随机的,那存进Redis也没有意义) 对于空数据的key有限的,重复率比较高的,用【粗暴法】。 | |
| 缓存击穿 | 含义 | 指一个key非常热点,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库上。 |
| 产生 | 关键在于某个热点的key失效了,导致大并发集中打在数据库上。 | |
| 危害 | 造成数据库短时间内承受大量请求而崩掉。 | |
| 解决 | 1-设置热点数据的缓存永不过期(或者过期时间比较大) 2-在缓存失效后,通过互斥锁或者队列来控制读数据写缓存的线程数量,比如某个key只允许一个线程查询数据和写缓存,其他线程等待。这种方式会阻塞其他的线程,此时系统的吞吐量会下降 3-设置双重缓存备份A和B,当A缓存失效时,使用B缓存 | |
| 缓存雪崩 | 含义 | 缓存在同一时间内大量键过期(失效) |
| 产生 | 1、第一种是Redis宕机 2、第二种可能就是采用了相同的过期时间 | |
| 危害 | 大波请求瞬间都落在了数据库中导致连接异常 | |
| 解决 | 事前:
事中:
事后:
|
永不过期实际包含两层意思:
- 物理不过期,针对热点key不设置过期时间
- 逻辑过期,把过期时间存在key对应的value里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建
6、【高频】Redis 如何实现高可用的?
单机可以支持约10w/s的QPS。
(1)完全基于内存,数据存在内存中,绝大部分请求是纯粹的内存操作,非常快速,跟传统的磁盘文件数据存储相比,避免了通过磁盘IO读取到内存这部分的开销。
(2)数据结构简单,对数据操作也简单。Redis中的数据结构是专门进行设计的,每种数据结构都有一种或多种数据结构来支持。Redis正是依赖这些灵活的数据结构,来提升读取和写入的性能。
(3)采用单线程,省去了很多上下文切换的时间以及CPU消耗,不存在竞争条件,不用去考虑各种锁的问题,不存在加锁释放锁操作,也不会出现死锁而导致的性能消耗。
(4)使用基于IO多路复用机制的线程模型,可以处理并发的链接。
(5)Redis直接自己构建了VM 机制 ,避免调用系统函数的时候,浪费时间去移动和请求
Redis的VM(虚拟内存)机制:暂时把不常访问的数据(冷数据)从内存交换到磁盘中,从而腾出内存空间用于其它需要访问的数据(热数据)。通过 VM 功能可以实现冷热数据分离,使热数据仍在内存中、冷数据保存到磁盘。
7、【高频】Reids如何实现分布式锁?
分布式锁:分布式系统中控制多个进程对共有资源的访问,叫分布式锁。
分布式锁具有的性质:
(1)互斥性。同一时间,只有一个客户端可以获取锁
(2)安全性。锁的获取和释放是同一客户端
(3)可用性。高可用/高性能 的获取锁与释放锁
(4) 可重入. 具备锁失效机制,防止死锁
(5)容错,服务器部分节点故障时客户端仍能正常获取和释放锁
(6)非阻塞锁特性,没有获取到锁将直接返回获取锁失败
Redis具体实现:
一、错误实现模式:setnx+expire 加锁
(setnx+expire间发生异常导致死锁,比如加锁后客户端直接挂了还没有设置有效期的锁,就无法进行释放锁,发生死锁)
setnx:key不存在set一个key为val的字符串,返回1;若key存在,返回0, 什么也不做保证互斥
expire :为key设置一个超时时间,单位为second,超过这个时间锁会自动释放,避免死锁。
二、正确实现(Redis2.6.12以后)
set原子方式加锁并给锁添加过期时间: SET KEY value NX EX expire-time ,其中NX和EX是固定值,
比较删除解锁:DEL KEY
竞争到锁的【客户端要做两件事】:1-设置锁的有效时间 目的是防死锁 2-分配客户端的唯一标识,目的是保证持锁人解锁, 这里value设置成唯一标识(比如uuid)
分布式锁实现比较【数据库】【Zookeeper】【Redis】
【数据库】
实现: 行锁 + 乐观锁。获取锁时插入一条数据,解锁时删除数据。
缺点:
1、单点故障问题。一旦数据库不可用,会导致整个系统崩溃
2、死锁问题(数据库锁没有失效时间)
【Zookeeper】
实现:加锁时在指定节点的目录下创建一个新节点,释放锁的时候删除这个临时节点
缺点:需要频繁地添加和删除节点,所以性能不如基于缓存实现的分布式锁。
比较:
| 理解的容易程度 | 数据库 > Redis缓存 > Zookeeper |
| 实现复杂度 | Zookeeper>= Redis缓存 > 数据库 |
| 性能 | Redis缓存 > Zookeeper >= 数据库 |
| 可靠性 | Zookeeper > Redis缓存 > 数据库 |
来自网络的对比图,出处了解一下三种分布式锁:关系型数据库分布式锁、redis缓存分布式锁、zookeeper分布式锁 - 温柔的风 - 博客园

8、【高频】Reids的集群架构方案?master-slave模式,以及哨兵模式
「Cluster 集群」或者「哨兵集群」的模式部署保证高可用。这两个模式都是基于「主从架构数据同步复制」实现的数据同步,而 Redis 的主从复制默认是异步的。
Redis 3.0加入了Redis的集群模式,实现了数据的分布式存储,对数据进行分片,将不同的数据存储在不同的master节点上面,从而解决了海量数据的存储问题。
【Redis集群】相关知识点
| 集群的搭建 |
|
| 集群搭建的算法 |
|
| 节点通讯机制 |
|
| 哈希槽的好处 | 使用哈希槽的好处就在于可以方便的添加或者移除节点,并且无论是添加删除或者修改某一个节点,都不会造成集群不可用的状态。当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了;当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了;哈希槽数据分区算法具有以下几种特点:
|
| 集群扩容 |
|
| 集群收缩 |
|
| 槽的迁移与指派 | 指令 CLUSTER ADDSLOTS 0 1 2 3 4 … 5000 |
master-slave模式
| 主从模式 | master节点负责写请求,然后异步同步给slave节点,从节点负责处理读请求。如果master宕机了,需要手动将从节点晋升为主节点,并且还要切换客户端的连接数据源。这就无法达到高可用,而通过哨兵模式就可以解决这一问题。 |
| 主从作用 | 1、读写分离; 2、容灾恢复。 |
| 主从如何操作 | 1、配从(库)不配主(库); 2、从库配置:slaveof [主库IP] [主库端口]; 补充:每次slave与master断开后,都需要重新连接,除非你配置进redis.conf文件; 键入info replication 可以查看redis主从信息。 |
| 常用对策 | 1、一主二仆 : 一个Master,两个Slave,Slave只能读不能写;当Slave与Master断开后需要重新slave of连接才可建立之前的主从关系;Master挂掉后,Master关系依然存在,Master重启即可恢复。 2、薪火相传: 上一个Slave可以是下一个Slave的Master,Slave同样可以接收其他slaves的连接和同步请求,那么该slave作为了链条中下一个slave的Master,如此可以有效减轻Master的写压力。如果slave中途变更转向,会清除之前的数据,重新建立最新的。 3、反客为主:当Master挂掉后,Slave可键入命令 slaveof no one使当前redis停止与其他Master redis数据同步,转成Master redis。 |
| 复制原理 | 1、Slave启动成功连接到master后会发送一个sync命令; 2、Master接到命令启动后的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步; 3、全量复制:而slave服务在数据库文件数据后,将其存盘并加载到内存中; 4、增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步; 5、但是只要是重新连接master,一次完全同步(全量复制)将被自动执行。 |
| 复制的缺点 | 复制延迟 | 系统繁忙 或 Slave机器数量的增加也会使得这个问题更加严重 |
哨兵模式
| 哨兵原理 | 【哨兵】相当于一台只提供了订阅功能的redis服务器 【客户端】只需要订阅哨兵的指定频道,当发生故障转移后,该频道就可以收到新的主节点信息。 哨兵主节点信息会发布到这个频道中:+switch-master |
| 主要任务 |
|
| 哨兵模式搭建 |
|
| 工作原理 |
|
| 哨兵模式优点 | 1. 哨兵集群,基于主从复制模式,所有的主从配置优点,它全有 2. 主从可以切换,故障可以转移,系统的可用性就会更好 3.哨兵模式就是主从模式的升级,手动到自动,更加健壮 |
| 哨兵模式缺点 | 1.Redis不好在线扩容的,集群容量一旦到达上限,在线扩容十分麻烦! 2.实现哨兵模式的配置其实是很麻烦的,里面有很多选择 |
9、【中频】Redis的过期策略?过期键删除如何实现?
9-1 三种过期删除的策略比较(定时删除、惰性删除、定期删除)
| 定时删除 | 设置某个 key 的过期时间同时,创建定时器,定时器在该过期时间到来时,立即执行删除操作 |
| |
| 惰性删除 | 当键值对过期时,只有再次用到这个键值对时才去检查删除这个键值对,如用不着,这个键值对会一直存在。 |
| |
| 定期删除 | 定期删除是对上面两种删除策略的一种整合和折中 每个一段时间就对一些 key 进行采样检查,检查是否过期,如果过期就进行删除 1、采样一定个数的key,采样的个数可以进行配置,并将其中过期的 key 全部删除; 2、如果过期 key 的占比超过 |
|
9-2 redis采用的是定期删除+惰性删除策略
redis采用的是定期删除+惰性删除策略
定期删除,redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms,全部key进行检查,redis岂不是卡死)。
因此,如果只采用定期删除策略,会导致很多key到时间没有删除。于是,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。
采用定期删除+惰性删除就没其他问题了么?
不是的,如果定期删除没删除key。然后你也没即时去请求key,也就是说惰性删除也没生效。这样,redis的内存会越来越高。那么就应该采用内存淘汰机制。
9-3、Redis内存淘汰机制
在redis.conf中有一行配置 maxmemory-policy volatile-lru 该配置就是配内存淘汰策略的
volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
no-enviction(驱逐):禁止驱逐数据,新写入操作会报错
ps:如果没有设置 expire 的key, 不满足先决条件(prerequisites); 那么 volatile-lru, volatile-random 和 volatile-ttl 策略的行为, 和 no-eviction(不删除) 基本上一致。
10、【普通】memcache与redis区别
(1)redis支持更丰富的数据类型(支持更复杂的应用场景)
| redis: String, Hash, List, Set, zSet | memcache : String |
(2)redis支持数据的持久化
| Redis 支持持久化:可将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用 |
| Memecache不支持数据持久化 |
(3)集群模式,分布式
| Redis Cluster 实现了分布式的支持。redis目前是原生支持cluster集群模式 |
| Memcached 不支持分布式,只能通过在客户端使用一致性哈希来实现分布式存储,这种方式在存储和查询时都需要先在客户端计算一次数据所在的节点。 |
(4)网络模型不同
| Redis使用 单线程的多路IO复用模型 | memcached是多线程,非阻塞IO复用的网络模型 |
(5)过期策略不同
| Redis同时使用了惰性删除与定期删除 | memcached过期数据的删除策略只用了惰性删除 |
(6)内存管理机制不同
| Redis 中,并不是所有数据都一直存储在内存中,可以将一些很久没用的 value 交换到磁盘 |
| Memcached 的数据则会一直在内存中。(Memcached 将内存分割成特定长度的块来存储数据,以完全解决内存碎片的问题。但是这种方式会使得内存的利用率不高,例如块的大小为 128 bytes,只存储 100 bytes 的数据,那么剩下的 28 bytes 就浪费掉了。) |
11、【普通】redis为什么单线程的
数据库和redis保持缓存一致性?强一致性和最终一致性都要设计
2.聊聊redis使用,假设我们redis集群中存了很多数据,这些数据还不能删,然后在使用的过程中redis集群内存占用过大怎么解决
3.redis大key问题怎么解决,比如一个key对应的value有几十万的byte
本文总结了Redis面试中常见的高频问题,包括Redis的网络模型、数据类型、持久化方式、缓存策略、高可用实现、分布式锁以及集群架构。详细解答了zSet的底层实现、过期策略以及与memcache的区别。通过对Redis特性和实战应用的深入剖析,帮助读者准备Redis相关的面试。

被折叠的 条评论
为什么被折叠?



