Redis面试题超详细(2024最新)

1、Redis是单线程执行还是多线程执行?它有线程安全问题吗?为什么吗?
Redis版本在6.0之前都是使用的单线程运行的。所有的客户端的请求处理、命令执行以及数据读写操作都是在一个主线程中完成得。这种设计目的就是为了防止多线程环境下的锁竞争和上下文切换所带来的性能开销,这样保证在高并发场景下的性能

Redis版本在6.0中,开始引入了多线程的支持,但是这仅限于网络I/O层面,即在网络请求阶段使用工作线程进行处理,对于指令的执行过程,仍然是在主线程来处理,所以不会存在多个线程通知执行操作指令的情况

关于线程安全问题,从Redis服务层面俩看,Redis Server本身就是一个线程安全按的K-V数据库,也就是说在Redis Server上面执行的指令,不需要任何同步机制,不会存在线程安全问题

2、在实际工作中,使用Redis实现了哪些业务场景?(最好结合自己做过的项目描述)
Redis在实际工作中广泛应用于多种业务场景,以下是一些常见的例子:

缓存:Redis作为Key-Value形态的内存数据库,最先会被想到的应用场景就是作为数据缓存。Redis提供了键过期功能,也提供了键淘汰策略,所以Redis用在缓存的场合非常多

排行榜:很多网站都有排行榜应用,如京东的月度销量榜单、商品按时间上新排行榜等。Redis提供的有序集合(zset)数据类

分布式会话:在集群模式下,一般会搭建以Redis等内存等内存数据库为中心的session服务,session不再由容器管理,而是由session服务及内存数据库管理

分布式锁:在高并发的情景,可以利用Redis的setnx功能来编写分布式锁

3、Redis常用数据类型有哪些?
Redis中,常见的数据类型有如下几种:

字符串(String):最简单的数据类型,可以包含任意数据,如文本、二进制数据等。常见的使用场景是存储Session信息、存储缓存信息、存储整数信息,可以使用incr实现整数+1,使用decr实现整数-1
列表(List):有序的字符串元素集合,支持双端进行插入和删除操作,可以用作队列或栈
哈希(Hash):用于存储对象,类似于关联数组。每个哈希可以包含字段和与之相关联的值。常见使用场景是存储Session信息、存储商品的购物车,购物车非常适用于哈希字典表示,使用人员唯一编号作为字典的key,value值可以存储商品的id和数量等信息、存储详情页等信息
集合(Set):一个无序并唯一的键值集合。它常见的使用场景是是仙女关注功能,比如关注我的人和我关注的人,使用集合存储,可以保证人员不重复
有序集合(Sorted Set):使用zset表示,相当于Set集合类型多了一个排序属性score(分值)。它常见的使用场景是可以用来存储排名信息,关注列表功能,这样就可以根据关注实现排序展示

4、存储Session信息你会使用哪种数据类型?为什么?

存储数据简单(不涉及局部更新):使用String类型存Session,这样做的优缺点如下:

优点:
存取操作简单直观,只需要单个键执行操作即可
多余小型Session,存储开销相对于较小
缺点:
如果Session数据复杂或者需要频繁更新其中的部分字段,则每次更新都需要重新序列化整个Session对象
不利于查询Session内特定字段值
存储数据复杂(涉及局部更新):如果Session数据结构复杂且需要频繁更新或查询其中个别字段,通常建议使用哈希表存储Session。每个Session视为一个独立的哈希表,Session ID作为key,Sesion内各个字段作为field-value对存储在哈希表中。示例:HSET session:123 userId 123 username user1,这样做的优缺点如下:

优点:
可以方便地进行字段级别的读写操作,例如 HGET session:23 userd 和 HSET session:123 lastAccessTime now
更新部分字段时无需修改整个Session内容
缺点:
相对于简单的字符串存储,哈希表占用的空间可能更大,尤其时当Session数据包含多个值的时候
小结: 如果 Session 数据结构复杂且需要频繁更新或查询其中的个别字段,通常建议使用哈希表来存储 Session;而在 Session 数据较为简单、不涉及局部更新的情况下,使用字符串存储也是可行的选择

5、使用Redis如何实现分布式锁?
实现分布式锁

使用Redis实现分布式锁可以通过setnx(set if not exists)命令实现,但当我们使用setnx创建键值成功时,则表中加锁成功,否则代码加锁失败,实现示例如下:

127.0.0.1:6379> setnx lock true
(integer) 1#创建锁成功
#逻辑业务处理..

当我们重复加锁时,只有第一次会加锁成功

127.8..1:6379> setnx lock true # 第一次加锁
(integer) 1
127.8.8.1:6379> setnx lock true # 第二次加锁
(integer) 0

从上述命令可以看出,我们可以看执行结果返回是不是1,就可以看出是否加锁成功

释放分布式锁

127.0.0.1:6379> de1 lock
(integer) 1 #释放锁

然而,如果使用 setnx lock true 实现分布式锁会存在死锁问题,以为 setnx 如未设置过期时间,锁忘记删了或加锁线程宕机都会导致死锁,也就是分布式锁一直被占用的情况

解决死锁问题

死锁问题可以通过设置超时时间来解决,如果超过了超时时间,分布锁会自动释放,这样就不会存在死锁问题了也就是 setnx和 expire 配合使用,在 Redis 2.6.12 版本之后,新增了一个强大的功能,我们可以使用一个原子操作也就是一条命令来执行 setnx 和expire 操作了,实现示例如下:

127.0.0.1:6379> set lock true ex 3 nx
OK #创建锁成功
127...1:6379> set lock true ex 3 nx
(ni1) #在锁被占用的时候,企图获取锁失败

其中ex为设置超时时间, nx 为元素非空判断,用来判断是否能正常使用锁的。
因此,我们在 Redis 中实现分布式锁最直接的方案就是使用 set key value ex timeout nx 的方式来实现。

6、Redis 是单进程单线程的吗?
Redis 是单进程单线程的,redis 利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。

7、Redis 的持久化机制是什么?各自的优缺点?
Redis提供两种持久化机制 RDB 和 AOF 机制:

1、RDB(Redis DataBase)持久化方式:
是指用数据集快照的方式半持久化模式)记录 redis 数据库的所有键值对,在某个时间点将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的文件,达到数据恢复。

优点:

(1)只有一个文件 dump.rdb,方便持久化。

(2)容灾性好,一个文件可以保存到安全的磁盘。

(3)性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO最大化。使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis的高性能)

(4)相对于数据集大时,比 AOF 的启动效率更高。

缺点:

数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候

2、AOF(Append-only file) 持久化方式:
是指所有的命令行记录以 redis 命令请求协议的格式完全持久化存储)保存为 aof 文件。

优点:

(1)数据安全,aof 持久化可以配置 appendfsync 属性,有 always,每进行一次命令操作就记录到 aof 文件中一次。

(2)通过 append 模式写文件,即使中途服务器宕机,可以通过 redis-check-aof工具解决数据一致性问题。

(3)AOF 机制的 rewrite 模式。AOF 文件没被 rewrite 之前(文件过大时会对命令进行合并重写),可以删除其中的某些命令(比如误操作的 flushall))

缺点:

(1)AOF 文件比 RDB 文件大,且恢复速度慢。

(2)数据集大的时候,比 rdb 启动效率低。

8、redis 过期键的删除策略?
(1)定时删除:在设置键的过期时间的同时,创建一个定时器 timer。
让定时器在键的过期时间来临时,立即执行对键的删除操作。

(2)惰性删除:放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。

(3)定期删除:每隔一段时间程序就对数据库进行一次检查,删除里面的过期键。至于要删除多少过期键,以及要检查多少个数据库,则由算法决定。

9、Redis 的回收策略(淘汰策略)?
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(驱逐):禁止驱逐数据

注意这里的 6 种机制,volatile 和 allkeys 规定了是对已设置过期时间的数据集淘汰数据还是从全部数据集淘汰数据,后面的 lru、ttl 以及 random 是三种不同的淘汰策略,再加上一种 no-enviction 永不回收的策略。

使用策略规则:

(1)如果数据呈现幂律分布,也就是一部分数据访问频率高,一部分数据访问频率低,则使用 allkeys-lru
(2)如果数据呈现平等分布,也就是所有的数据访问频率都相同,则使用allkeys-random

10、Redis 的同步机制了解么?
答:Redis 可以使用主从同步,从从同步。第一次同步时,主节点做一次 bgsave,并同时将后续修改操作记录到内存 buffer,待完成后将 rdb 文件全量同步到复制节点,复制节点接受完成后将 rdb 镜像加载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。

11、是否使用过 Redis 集群,集群的原理是什么?
(1)Redis Sentinal 着眼于高可用,在 master 宕机时会自动将 slave 提升为master,继续提供服务。

(2)Redis Cluster 着眼于扩展性,在单个 redis 内存不足时,使用 Cluster 进行分片存储。

12、说说 Redis 哈希槽的概念?(关于哈希槽可以看看我主页其他文章)
Redis 集群没有使用一致性 hash,而是引入了哈希槽的概念,Redis 集群有16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽,集群的每个节点负责一部分 hash 槽。

13、Redis 集群会有写操作丢失吗?为什么?
Redis 并不能保证数据的强一致性,这意味这在实际中集群在特定的条件下可能会丢失写操作。

14、Redis 集群之间是如何复制的?
答:异步复制

15、Redis 集群最大节点个数是多少?
答:16384 个。

16、Redis 集群如何选择数据库?
答:Redis 集群目前无法做数据库选择,默认在 0 数据库。

17、怎么测试 Redis 的连通性?
答:使用 ping 命令。

18、怎么理解 Redis 事务?
答:

(1)事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

(2)事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。

19、Redis 事务相关的命令有哪几个?
答:MULTI、EXEC、DISCARD、WATCH

20、Redis key 的过期时间和永久有效分别怎么设置?
EXPIRE 和 PERSIST 命令。

21、Redis 如何做内存优化?
答:尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。比如你的 web 系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的 key,而是应该把这个用户的所有信息存储到一张散列表里面。

22、MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中的数据都是热点数据?
Redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。

相关知识:Redis 提供 6 种数据淘汰策略:

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(驱逐):禁止驱逐数据

23、Redis 最适合的场景?
1、会话缓存(Session Cache)
最常用的一种使用 Redis 的情景是会话缓存(session cache)。用 Redis 缓存会话比其他存储(如 Memcached)的优势在于:Redis 提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗? 幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用 Redis 来缓存会话的文档。甚至广为人知的商业平台Magento 也提供 Redis 的插件。

2、全页缓存(FPC)
除基本的会话 token 之外,Redis 还提供很简便的 FPC 平台。回到一致性问题,即使重启了 Redis 实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似 PHP 本地 FPC。 再次以 Magento 为例,Magento提供一个插件来使用 Redis 作为全页缓存后端。 此外,对 WordPress 的用户来说,Pantheon 有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。

3、队列
Reids 在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得 Redis能作为一个很好的消息队列平台来使用。Redis 作为队列使用的操作,就类似于本地程序语言(如 Python)对 list 的 push/pop 操作。 如果你快速的在 Google中搜索“Redis queues”,你马上就能找到大量的开源项目,这些项目的目的就是利用 Redis 创建非常好的后端工具,以满足各种队列需求。例如,Celery 有一个后台就是使用 Redis 作为 broker,你可以从这里去查看。

4,排行榜/计数器
Redis 在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis 只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的 10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可: 当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行: ZRANGE user_scores 0 10 WITHSCORES Agora Games 就是一个很好的例子,用 Ruby 实现的,它的排行榜就是使用 Redis 来存储数据的,你可以在这里看到。

5、发布/订阅
最后(但肯定不是最不重要的)是 Redis 的发布/订阅功能。发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用 Redis 的发布/订阅功能来建立聊天系统!

24、假如 Redis 里面有 1 亿个 key,其中有 10w 个 key 是以某个固定的已知的前缀开头的,如果将它们全部找出来?
使用 keys 指令可以扫出指定模式的 key 列表。

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

这个时候你要回答 redis 关键的一个特性:redis 的单线程的。keys 指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用 scan 指令,scan 指令可以无阻塞的提取出指定模式的 key 列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用 keys 指令长。

25、如果有大量的 key 需要设置同一时间过期,一般需要注意什么?
如果大量的 key 过期时间设置的过于集中,到过期的那个时间点,redis 可能会出现短暂的卡顿现象。一般需要在时间上加一个随机值,使得过期时间分散一些。

26、使用过 Redis 分布式锁么,它是什么回事?
先拿 setnx 来争抢锁,抢到之后,再用 expire 给锁加一个过期时间防止锁忘记了释放。
如果在 setnx 之后执行 expire之前进程意外 crash 或者要重启维护了,那会怎么样?
答: set 指令有非常复杂的参数,这个应该是可以同时把 setnx 和expire 合成一条指令来用的!

27、Redis的主从复制是什么?

Redis的主从复制是指将一个Redis实例(主节点)的数据复制到其他Redis实例(从节点)。主节点负责接收写操作并将写操作传播给从节点,从节点则复制主节点的数据。主从复制可以实现数据的备份、扩展读性能和提高高可用性。

28、Redis的数据一致性如何保证?

Redis的数据一致性主要通过以下机制来保证:

主从复制:当Redis的主节点更新数据时,会将更新操作传播给从节点,从节点通过复制主节点的数据来保持一致性。
哨兵模式:Redis的哨兵模式用于监控主节点的状态,并在主节点故障时自动将一个从节点升级为新的主节点,以保持数据的可用性和一致性。
Redis Cluster:Redis Cluster是一种分布式解决方案,通过数据分片和复制来实现数据的分布式存储和高可用性。

29、如何保证Redis的高可用性?

为了保证Redis的高可用性,可以采取以下措施:

主从复制:通过配置Redis主从复制,当主节点故障时,可以自动切换到从节点作为新的主节点,提高系统的可用性。
哨兵模式:使用Redis的哨兵模式可以监控主节点的状态,并在主节点故障时自动进行故障转移,选举新的主节点。
Redis Cluster:通过Redis Cluster可以将数据分布在多个节点上,并在节点故障时进行自动重新分片和故障转移,保证系统的高可用性和扩展性。
30、Redis的性能调优技巧有哪些?

Redis的性能调优技巧包括以下几个方面:

使用合适的数据结构:选择适当的数据结构来存储和操作数据,以提高读写性能。
使用批量操作和管道技术:通过批量操作和管道技术可以减少网络开销和降低延迟,提高性能。
设置合理的最大内存限制:根据系统的实际内存情况,设置合理的最大内存限制,避免过度使用内存导致性能问题。
合理配置持久化策略:根据实际需求选择适当的持久化方式,并设置合理的持久化频率,平衡数据持久化和性能之间的关系。
合理使用缓存过期时间:根据业务需求和数据特性,设置合理的缓存过期时间,避免缓存数据过期或占用过多的内存。
避免过度使用阻塞操作:尽量避免使用阻塞操作,如阻塞的命令和阻塞的事件通知,以充分利用Redis的异步特性和高并发能力。

可以关注,微信订阅号“猿来编码”的文章查看更多面试题或者其他工具分享

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值