当前位置: 首页 > news >正文

【Redis面试篇】Redis高频八股汇总

目录

基础 + 数据结构

1. 为什么用 Redis 作为 MySQL 的缓存?

2. Redis 数据类型以及使用场景分别是什么?

3. 五种常见的 Redis 数据类型是怎么实现?

4. 跳表是怎么实现的?跳表是怎么设置层高的?

5. Redis为什么使用跳表而不是用平衡术、红黑树或B+树?

6. 介绍一下 Redis 中的 listpack?

7. 哈希表是怎么扩容的?

8. 哈希表扩容的时候,有读请求怎么查?

9. String 是使用什么存储的?为什么不用 c 语言中的字符串?

线程模型

10. Redis为什么快?

11. Redis 是单线程还是多线程?

12. Redis哪些地方使用了多线程?

13. Redis怎么实现的io多路复用?

14. Redis的网络模型是怎样的?

15. Redis 6.0 之前为什么使用单线程?

16. Redis 6.0 之后为什么引入了多线程?

持久化

17. Redis 如何实现数据不丢失?

18. RDB 快照是如何实现的呢?

19. AOF 日志是如何实现的?

20. 为什么会有混合持久化?

内存回收

21. Redis 使用的过期删除策略是什么?

22. Redis 持久化时,对过期键会如何处理的?

23. Redis 主从模式中,对过期键会如何处理?

24. Redis 内存满了,会发生什么?

25. Redis 内存淘汰策略有哪些?

26. LRU 算法和 LFU 算法有什么区别?

分布式缓存

27. Redis主从复制是怎么实现的?

28. Redis主从节点时长连接还是短连接?

29. Redis 是同步复制还是异步复制?

30. Redis哨兵机制是如何工作的?

31. 由哪个哨兵进行主从故障转移?

32. 主从故障转移的过程是怎样的?

33. 哨兵集群是如何组成的?

34. 为什么需要Redis Cluster,有什么好处?

35. 客户端是怎样知道该访问哪个分片的?

36. 实例上并没有相应的数据,会怎么样?

37. Redis集群中各个节点之间是怎么通信的?

38. 集群内节点出现故障怎么办(故障转移)?

39. 为什么Redis Cluster的Hash Slot 是16384?

性能优化

40. Redis性能优化的方法有哪些?

41. Redis 的大 key 如何处理?

43. Redis 管道(Pipeline)有什么用?

生产问题

44. 缓存穿透、缓存击穿、缓存雪崩是什么?如何解决?

45. 布隆过滤器的原理?

46. 如何保证缓存与数据库的数据一致性?


基础 + 数据结构

1. 为什么用 Redis 作为 MySQL 的缓存?

Redis 之所以被广泛使用,主要因为它具备「高性能」和「高并发」两大核心特性。

1. Redis 具备高性能

当用户首次访问 MySQL 中的某些数据时,由于需要从硬盘读取,速度较慢。如果将这些数据缓存在 Redis 中,后续访问时就能直接从内存获取。由于 Redis 的操作基于内存,读写速度极快,显著提升了数据访问效率。

当 MySQL 中的数据发生变更时,只需同步更新 Redis 缓存中对应的数据即可。不过这会涉及 Redis 和 MySQL 双写一致性的问题,我们稍后会详细讨论。

2. Redis 具备高并发

  • 性能对比:单台 Redis 的 QPS(每秒查询数)可达 10w+,而单台 MySQL 的 QPS 通常难以突破 1w。Redis 的处理能力是 MySQL 的 10 倍以上

  • 高并发优势:将部分数据从数据库迁移到 Redis 缓存后,大量用户请求可以直接由 Redis 处理,减轻数据库压力,显著提升系统整体的并发承载能力

2. Redis 数据类型以及使用场景分别是什么?

3. 五种常见的 Redis 数据类型是怎么实现?

4. 跳表是怎么实现的?跳表是怎么设置层高的?

跳表在创建节点时候,会生成范围为[0-1]的一个随机数,如果这个随机数小于 0.25(相当于概率25%),那么层数就增加1层,然后继续生成下一个随机数,直到随机数的结果大于 0.25 结束,最终确定该节点的层数。

5. Redis为什么使用跳表而不是用平衡术、红黑树或B+树?

1. 平衡树 vs 跳表

  • 时间复杂度:平衡树和跳表的插入、删除、查询操作均为 O(log⁡n)O(logn)。

  • 范围查询:两者均支持高效的范围查询(平衡树通过中序遍历,跳表通过链表遍历)。

  • 平衡维护

    • 平衡树需通过旋转操作强制保持绝对平衡,开销较大;

    • 跳表采用概率平衡,实现更简单,操作更快。

2. 红黑树 vs 跳表

  • 实现复杂度:跳表无需旋转或染色(红黑变换),实现更简单。

  • 区间查询:跳表的区间查询效率高于红黑树,因其天然支持有序链表遍历。

3. B+ 树 vs 跳表

  • 适用场景

    • B+ 树:适合磁盘存储的数据库/文件系统,通过减少IO次数定位数据;

    • 跳表:适合内存数据库(如Redis),无需处理大量数据索引。

  • 内存效率

    • B+ 树需维护严格的节点分裂与合并

    • 跳表通过随机索引维护,节省内存,插入时仅需调整局部链表和索引。

  • 实现简易性:跳表实现更简单,适合Redis的zset结构需求。

6. 介绍一下 Redis 中的 listpack?

7. 哈希表是怎么扩容的?

8. 哈希表扩容的时候,有读请求怎么查?

查找一个 key 的值的话,先会在「哈希表 0」里面进行查找,如果没找到,就会继续到 哈希表1 里面进行找到。

9. String 是使用什么存储的?为什么不用 c 语言中的字符串?

2、3、9 见【Redis原理】Redis基本数据类型及其原理-CSDN博客

4、6、7 见【Redis原理】Redis数据结构底层原理 -CSDN博客

线程模型

10. Redis为什么快?

  • Redis 的大部分操作都在内存中完成,并且采用了高效的数据结构,因此 Redis 瓶颈可能是机器的内存或者网络带宽,而并非 CPU,既然 CPU 不是瓶颈,那么自然就采用单线程的解决方案了;

  • Redis 采用单线程模型可以避免了多线程之间的竞争,省去了多线程切换带来的时间和性能上的开销,而且也不会导致死锁问题

  • Redis 采用了 I/O 多路复用机制处理大量的客户端 Socket 请求,IO 多路复用机制是指一个线程处理多个 IO 流,就是我们经常听到的 select/epoll 机制。简单来说,在 Redis 只运行单线程的情况下,该机制允许内核中,同时存在多个监听 Socket 和已连接 Socket。内核会一直监听这些 Socket 上的连接请求或数据请求。一旦有请求到达,就会交给 Redis 线程处理,这就实现了一个 Redis 线程处理多个 IO 流的效果。

11. Redis 是单线程还是多线程?

  • Redis 单线程指的是「接收客户端请求->解析请求 ->进行数据读写等操作->发送数据给客户端」这个过程是由一个线程(主线程)来完成的,这也是我们常说 Redis 是单线程的原因。

  • 但是,Redis 程序并不是单线程的,Redis 在启动的时候,是会启动后台线程(BIO)的:

    • Redis 在 2.6 版本,会启动 2 个后台线程,分别处理关闭文件、AOF 刷盘这两个任务;

    • Redis 在 4.0 版本之后,新增了一个新的后台线程,用来异步释放 Redis 内存,也就是 lazyfree 线程。例如执行 unlink key / flushdb async / flushall async 等命令,会把这些删除操作交给后台线程来执行,好处是不会导致 Redis 主线程卡顿。因此,当我们要删除一个大 key 的时候,不要使用 del 命令删除,因为 del 是在主线程处理的,这样会导致 Redis 主线程卡顿,因此我们应该使用 unlink 命令来异步删除大 key。

  • 之所以 Redis 为「关闭文件、AOF 刷盘、释放内存」这些任务创建单独的线程来处理,是因为这些任务的操作都是很耗时的,如果把这些任务都放在主线程来处理,那么 Redis 主线程就很容易发生阻塞,这样就无法处理后续的请求了。

  • 后台线程相当于一个消费者,生产者把耗时任务丢到任务队列中,消费者(BIO)不停轮询这个队列,拿出任务就去执行对应的方法即可。

  • 关闭文件、AOF 刷盘、释放内存这三个任务都有各自的任务队列:

    • BIO_CLOSE_FILE,关闭文件任务队列:当队列有任务后,后台线程会调用 close(fd),将文件关闭;

    • BIO_AOF_FSYNC,AOF刷盘任务队列:当 AOF 日志配置成 everysec 选项后,主线程会把 AOF 写日志操作封装成一个任务,也放到队列中。当发现队列有任务后,后台线程会调用 fsync(fd),将 AOF 文件刷盘。

    • BIO_LAZY_FREE,lazy free 任务队列:当队列有任务后,后台线程会 free(obj) 释放对象 / free(dict) 删除数据库所有对象 / free(skiplist) 释放跳表对象;

12. Redis哪些地方使用了多线程?

同11

13. Redis怎么实现的io多路复用?

  • 因为 Redis 是跑在「单线程」中的,所有的操作都是按照顺序线性执行的,但是由于读写操作等待用户输入或输出都是阻塞的,所以 I/O 操作在一般情况下往往不能直接返回,这会导致某一文件的 I/O 阻塞,致整个进程无法对其它客户提供服务。而 I/O多路复用就是为了解决这个问题而出现的。为了让单线程(进程)的服务端应用同时处理多个客户端的事件,Redis 采用了 IO 多路复用机制

  • 这里“多路”指的是多个网络连接客户端,“复用”指的是复用同一个线程(单进程)I/O 多路复用其实是使用一个线程来检查多个 Socket 的就绪状态,在单个线程中通过记录跟踪每一个 socket (I/O流) 的状态来管理处理多个 I/O 流

如下图是 Redis 的 I/O 多路复用模型

  • 以 Redis 的 I/O 多路复用程序 epoll 函数为例。多个客户端连接服务端时,Redis 会将客户端 socket 对应的 fd 注册进 epoll,然后 epoll 同时监听多个文件描述符(FD)是否有数据到来,如果有数据来了就通知事件处理器赶紧处理,这样就不会存在服务端一直等待某个客户端给数据的情形。

  • 整个文件事件处理器是在单线程上运行的,但是通过 I/O 多路复用模块的引入,实现了同时对多个 FD 读写的监控,当其中一个 client 端达到写或读的状态,文件事件处理器就马上执行,从而就不会出现 I/O 堵塞的问题,提高了网络通信的性能

  • Redis 的 I/O 多路复用模式使用的是 Reactor 设计模式的方式来实现。

14. Redis的网络模型是怎样的?

Redis 6.0 版本之前,是用的是单Reactor单线程的模式

单 Reactor 单进程的方案因为全部工作都在同一个进程内完成,所以实现起来比较简单,不需要考虑进程间通信,也不用担心多进程竞争

但是,这种方案存在 2 个缺点

  • 第一个缺点,因为只有一个进程,无法充分利用 多核 CPU 的性能

  • 第二个缺点,Handler 对象在业务处理时,整个进程是无法处理其他连接的事件的,如果业务处理耗时比较长,那么就造成响应的延迟

所以,单 Reactor 单进程的方案不适用计算机密集型的场景,只适用于业务处理非常快速的场景

Redis 是由 C 语言实现的,在 Redis 6.0 版本之前采用的是「单 Reactor 单进程」的方案,因为 Redis 业务处理主要是在内存中完成,操作的速度很快,性能瓶颈不在 CPU 上,所以 Redis 对于命令的处理是单进程的方案。

到 Redis 6.0 之后,就将网络I/O的处理改成多线程的方式了,目的是因为随着网络硬件的性能提升,Redis 的性能瓶颈有时会出现在网络 I/O 的处理上

所以为了提高网络 I/O 的并行度,Redis 6.0 对于网络 I/O采用多线程来处理。但是对于命令的执行,Redis 仍然使用单线程来处理,所以大家不要误解 Redis 有多线程同时执行命令。

 

15. Redis 6.0 之前为什么使用单线程?

CPU 并不是制约 Redis 性能表现的瓶颈所在,更多情况下是受到内存大小和网络I0的限制,所以 Redis 核心网络模型使用单线程并没有什么问题,如果你想要使用服务的多核CPU,可以在一台服务器上启动多个节点或者采用分片集群的方式。

使用了单线程后,可维护性高,多线程模型虽然在某些方面表现优异,但是它却引入了程序执行顺序的不确定性,带来了并发读写的一系列问题,增加了系统复杂度、同时可能存在线程切换、甚至加锁解锁死锁造成的性能损耗。

16. Redis 6.0 之后为什么引入了多线程?

虽然 Redis 的主要工作(网络 I/O 和执行命令)一直是单线程模型,但是在 Redis 6.0 版本之后,也采用了多个 I/O 线程来处理网络请求,这是因为随着网络硬件的性能提升,Redis 的性能瓶颈有时会出现在网络 I/O 的处理上

所以为了提高网络 I/O 的并行度,Redis 6.0 对于网络 I/O采用多线程来处理。但是对于命令的执行,Redis 仍然使用单线程来处理,所以大家不要误解 Redis 有多线程同时执行命令。

Redis 官方表示,Redis 6.0 版本引入的多线程 I/O 特性性能提升至少是一倍以上

持久化

17. Redis 如何实现数据不丢失?

Redis 的读写操作都是在内存中,所以 Redis 性能才会高,但是当 Redis 重启后,内存中的数据就会丢失,那为了保证内存中的数据不会丢失,Redis 实现了数据持久化的机制,这个机制会把数据存储到磁盘,这样在 Redis 重启就能够从磁盘中恢复原有的数据。

Redis 共有三种数据持久化的方式

  • AOF 日志:每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里;

  • RDB 快照:将某一时刻的内存数据,以二进制的方式写入磁盘;

  • 混合持久化方式:Redis 4.0 新增的方式,集成了 AOF 和 RDB 的优点

18. RDB 快照是如何实现的呢?

19. AOF 日志是如何实现的?

20. 为什么会有混合持久化?

RDB 优点数据恢复速度快,但是快照的频率不好把握。频率太低,丢失的数据就会比较多,频率太高,就会影响性能。

AOF 优点丢失数据少,但是数据恢复不快

为了集成了两者的优点Redis 4.0 提出了混合使用 AOF 日志和内存快照,也叫混合持久化,既保证了 Redis 重启速度,又降低数据丢失风险

混合持久化工作在 AOF 日志重写过程,当开启了混合持久化时,在 AOF 重写日志时,fork 出来的重写子进程会先将与主线程共享的内存数据以 RDB 方式写入到 AOF 文件,然后主线程处理的操作命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以 AOF 方式写入到 AOF 文件,写入完成后通知主进程将新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件

也就是说,使用了混合持久化AOF 文件的前半部分是 RDB 格式的全量数据后半部分是 AOF 格式的增量数据

这样的好处在于,重启 Redis 加载数据的时候,由于前半部分是 RDB 内容,这样加载的时候速度会很快

加载完 RDB 的内容后,才会加载后半部分的 AOF 内容,这里的内容是 Redis 后台子进程重写 AOF 期间主线程处理的操作命令,可以使得数据更少的丢失

混合持久化优点

  • 混合持久化结合了 RDB 和 AOF 持久化的优点,开头为 RDB 的格式,使得 Redis 可以更快的启动,同时结合 AOF 的优点,有减低了大量数据丢失的风险

混合持久化缺点

  • AOF 文件中添加了 RDB 格式的内容,使得 AOF 文件的可读性变得很差

  • 兼容性差,如果开启混合持久化,那么此混合持久化 AOF 文件,就不能用在 Redis 4.0 之前版本了。

参考【Redis原理】Redis持久化——RDB与AOF-CSDN博客

内存回收

21. Redis 使用的过期删除策略是什么?

22. Redis 持久化时,对过期键会如何处理的?

Redis 持久化文件有两种格式:RDB(Redis Database)和 AOF(Append Only File),下面我们分别来看过期键在这两种格式中的呈现状态。

RDB 文件分为两个阶段,RDB 文件生成阶段和加载阶段。

  • RDB 文件生成阶段:从内存状态持久化成 RDB(文件)的时候,会对 key 进行过期检查,过期的键「不会」被保存到新的 RDB 文件中,因此 Redis 中的过期键不会对生成新 RDB 文件产生任何影响。

  • RDB 加载阶段:RDB 加载阶段时,要看服务器是主服务器还是从服务器,分别对应以下两种情况:

    • 如果 Redis 是「主服务器」运行模式的话,在载入 RDB 文件时,程序会对文件中保存的键进行检查,过期键「不会」被载入到数据库中。所以过期键不会对载入 RDB 文件的主服务器造成影响;

    • 如果 Redis 是「从服务器」运行模式的话,在载入 RDB 文件时,不论键是否过期都会被载入到数据库中。但由于主从服务器在进行数据同步时,从服务器的数据会被清空。所以一般来说,过期键对载入 RDB 文件的从服务器也不会造成影响。

AOF 文件分为两个阶段,AOF 文件写入阶段和 AOF 重写阶段。

  • AOF 文件写入阶段:当 Redis 以 AOF 模式持久化时,如果数据库某个过期键还没被删除,那么 AOF 文件会保留此过期键,当此过期键被删除后,Redis 会向 AOF 文件追加一条 DEL 命令来显式地删除该键值。

  • AOF 重写阶段:执行 AOF 重写时,会对 Redis 中的键值对进行检查,已过期的键不会被保存到重写后的 AOF 文件中,因此不会对 AOF 重写造成任何影响。

23. Redis 主从模式中,对过期键会如何处理?

当 Redis 运行在主从模式下时,从库不会进行过期扫描,从库对过期的处理是被动的。也就是即使从库中的 key 过期了,如果有客户端访问从库时,依然可以得到 key 对应的值,像未过期的键值对一样返回。

从库的过期键处理依靠主服务器控制,主库在 key 到期时,会在 AOF 文件里增加一条 del 指令,同步到所有的从库,从库通过执行这条 del 指令 来删除过期的 key。

24. Redis 内存满了,会发生什么?

在 Redis 的运行内存达到了某个阈值,就会触发内存淘汰机制,这个阈值就是我们设置的最大运行内存,此值在 Redis 的配置文件中可以找到,配置项为 maxmemory

25. Redis 内存淘汰策略有哪些?

26. LRU 算法和 LFU 算法有什么区别?

其余参考【Redis原理】Redis过期删除策略与内存淘汰策略-CSDN博客

分布式缓存

27. Redis主从复制是怎么实现的?

28. Redis主从节点时长连接还是短连接?

长连接

29. Redis 是同步复制还是异步复制?

Redis 主节点每次收到写命令之后,先写到内部的缓冲区,然后异步发送给从节点。

30. Redis哨兵机制是如何工作的?

31. 由哪个哨兵进行主从故障转移?

32. 主从故障转移的过程是怎样的?

33. 哨兵集群是如何组成的?

34. 为什么需要Redis Cluster,有什么好处?

35. 客户端是怎样知道该访问哪个分片的?

36. 实例上并没有相应的数据,会怎么样?

37. Redis集群中各个节点之间是怎么通信的?

38. 集群内节点出现故障怎么办(故障转移)?

39. 为什么Redis Cluster的Hash Slot 是16384?

【Redis原理】Redis分布式缓存——主从复制、哨兵机制与Redis Cluster-CSDN博客

性能优化

40. Redis性能优化的方法有哪些?

41. Redis 的大 key 如何处理?

  • 对大Key进行拆分。例如将含有数万成员的一个HASH Key拆分为多个HASH Key,并确保每个Key的成员数量在合理范围。在Redis集群架构中,拆分大Key能对数据分片间的内存平衡起到显著作用。

  • 对大Key进行清理。将不适用Redis能力的数据存至其它存储,并在Redis中删除此类数据。注意,要使用异步删除

  • 监控Redis的内存水位。可以通过监控系统设置合理的Redis内存报警阈值进行提醒,例如Redis内存使用率超过70%、Redis的内存在1小时内增长率超过20%等。

  • 对过期数据进行定期清理。堆积大量过期数据会造成大Key的产生,例如在HASH数据类型中以增量的形式不断写入大量数据而忽略了数据的时效性。可以通过定时任务的方式对失效数据进行清理。

43. Redis 管道(Pipeline)有什么用?

管道技术 (Pipeline) 是客户端提供的一种批处理技术,用于一次处理多个 Redis 命令,从而提高整个交互的性能。

普通命令模式,如下图所示:

管道模式,如下图所示:

使用管道技术 (Pipeline) 可以解决多个命令执行时的网络等待,它是把多个命令整合到一起发送给服务器端处理之后统一返回给客户端,这样就免去了每条命令执行后都要等待的情况,从而有效地提高了程序的执行效率。

但使用管道技术也要注意避免发送的命令过大,或管道内的数据太多而导致的网络阻塞

要注意的是,管道技术本质上是客户端提供的功能,而非 Redis 服务器端的功能。



【Redis原理】Redis性能优化-CSDN博客

生产问题

44. 缓存穿透、缓存击穿、缓存雪崩是什么?如何解决?

45. 布隆过滤器的原理?

46. 如何保证缓存与数据库的数据一致性?

【Redis原理】Redis生产问题——缓存穿透、缓存击穿、缓存雪崩和缓存与数据库的数据一致性-CSDN博客

 

http://www.dtcms.com/a/263432.html

相关文章:

  • 长短期记忆网络(LSTM):让神经网络拥有 “持久记忆力” 的神奇魔法
  • 周赛98补题
  • Go语言安装使用教程
  • Golang的多环境配置
  • 「Java流程控制」while循环
  • Redis 实现消息队列
  • 【软考高项论文】论信息系统项目的质量管理
  • js代码01
  • 【数据分析】环境数据降维与聚类分析教程:从PCA到可视化
  • uniapp+vue2 input不显示明文密码,点击小眼睛显示或隐藏密码
  • “对象创建”模式之原型模式
  • window显示驱动开发—全屏模式
  • SuperGlue:基于图神经网络的特征匹配技术解析
  • 【Linux系统部分】在Linux命令行中写一个简单的shell外壳
  • ansible的剧本文件一般放在什么地方?
  • creo 2.0学习笔记
  • Stanford_CS224W----Machine learning with graph
  • (5)pytest-yield操作
  • 实现ModbusTCP转Profinet网关协议转换功能的网关设备
  • 【python】langgraph环境安装的曲折办法
  • 问题分解提示法:用结构化方法破解LLM复杂任务难题
  • 信创项目oracle数据库迁移到达梦数据库需要会有哪些问题?如何解决?
  • 《Redis可扩展:轻松应对数据增长与流量高峰》
  • Python 数据分析与机器学习入门 (六):Seaborn 可视化技巧,图表更美观
  • 飞算 JavaAI 深度实战:从老项目重构到全栈开发的降本增效密码
  • Windows如何安装beego环境问题解
  • 正交视图三维重建2 笔记 2d线到3d线2 先生成3d线然后判断3d线在不在
  • 推进自动驾驶车辆智能:基于深度学习和多模态LLM的交通标志识别与鲁棒车道检测
  • 告别复杂爬虫!Perplexity AI辅助Python网页抓取
  • 爬虫详解:Aipy打造自动抓取代理工具