首页 > 数据库 >Redis面试题、知识点总结,一篇文章让Redis成为面试加分项

Redis面试题、知识点总结,一篇文章让Redis成为面试加分项

时间:2024-06-11 13:00:16浏览次数:34  
标签:知识点 面试题 AOF Redis RDB 日志 数据 节点

Redis面试题、知识点总结,一篇文章让Redis成为面试加分项

前言

参与了几次中大厂的面试,你会发现一面时对于八股文的考察也具有侧重点(MySQL=Redis > 网络 > 系统 >设计模式 > java集合> JVM >spring)

本文的目标就是通过这一篇文章让你能在面试时将Redis相关的问题回答漂亮。

所以整理问题时,本文会从一个问题出发(面试官会问),联想出更多问题(面试官可能会追问,也可以自己说:我还知道。。。)以求加分。(当你对一块知识了解的比较好时,就要想办法拉长这块内容的面试时长)

1.Redis基础

Redis了解吗?

Redis 是一种基于内存的数据库,对数据的读写操作都是在内存中完成,加上Redis对使用的数据结构做了优化,因此读写速度非常快,最常用于做缓存

[Redis基础联想1]:提到数据结构和缓存这两个关键字,尽量引出追问

[Redis基础联想2]: 为什么用 Redis 作为 MySQL 的缓存?:主要是因为 Redis 具备「高性能」和「高并发」两种特性

高性能是因为Redis是基于内存的,比直接使用MySQL在硬盘中读数据快很多。(提到MySQL可能会引出双写一致性问题)

高并发是指单台设备的Redis的QPS是MySQL的10倍,能到达10w+。

2.Redis数据结构

你知道哪些Redis的数据类型?

常见的有五种数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)、Zset(有序集合)

[数据类型联想1]:这些数据类型的应用场景有哪些?

  • String 类型的应用场景:缓存对象、常规计数、分布式锁、共享 session 信息等。
  • List 类型的应用场景:消息队列(但是有两个问题:1. 生产者需要自行实现全局唯一 ID;2. 不能以消费组形式消费数据)等。
  • Hash 类型:缓存对象、购物车等。
  • Set 类型:聚合计算(并集、交集、差集)场景,比如点赞、共同关注、抽奖活动等。
  • Zset 类型:排序场景,比如排行榜、电话和姓名排序等。

[数据类型联想2]:String底层数据结构知道吗?

SDS:简单动态字符串,是对c语言中char数组缺点的改进:

  • char数组不能保存二进制数据,因为其以’\n’作为字符串的结尾,而SDS使用整型数组保存数据,可以保存图片、视频等二进制数据。
  • char数组获取数组长度时间复杂度O(n),SDS维护一个len属性,做到了O(1)
  • char数组拼接字符串可能造成缓冲区溢出,SDS维护内存大小的属性,减去len属性就可以得到剩余可用内存检查是否够用,不够则扩容。

[数据类型联想3]:Zset底层数据结构知道吗?

答:压缩列表或跳表。

  • 如果有序集合的元素个数小于 128 个,并且每个元素的值小于 64 字节时,Redis 会使用压缩列表作为 Zset 类型的底层数据结构;
  • 如果有序集合的元素不满足上面的条件,Redis 会使用跳表作为 Zset 类型的底层数据结构;

在 Redis 7.0 中,压缩列表数据结构已经废弃了,交由 listpack 数据结构来实现了。

追问:压缩列表有什么问题,为什么废弃?

答:连锁更新,压缩列表每个节点会记录前一个节点的长度,记录这个长度默认需要一个字节,当一个字节保存不下时(超过254)会扩充到5个字节,当一个节点长度改变或插入节点时,可能会让下一个节点的记录长度扩充4个字节,使得整体长度变长,又可能导致下下一个节点长度改变,触发连锁反应,浪费资源。

再追问:那跳表了解吗?

跳表是一个可以快速查找的有序链表, 搜索、插入、删除操作的时间复杂度跟红黑树都是一样量级的均为O(logn)

再再最追问:那Redis为什么用跳表不用红黑树呢?

跳表不采用红黑树、平衡二叉树这类平衡树的原因主要有两点(答出两点就够了):

  • 在做范围查找的时候,跳表比平衡树操作要简单。在平衡树上,我们找到指定范围的小值之后,还需要以中序遍历的顺序继续寻找其它不超过大值的节点。如果不对平衡树进行一定的改造,这里的中序遍历并不容易实现。而在跳表上进行范围查找就非常简单,只需要在找到小值之后,对第 1 层链表进行若干步的遍历就可以实现。
  • 从算法实现难度上来比较,跳表比平衡树要简单得多。平衡树的插入和删除操作可能引发子树的调整,逻辑复杂,而跳表的插入和删除只需要修改相邻节点的指针,操作简单又快速。

3.Redis线程模型

Redis 是单线程吗?(经典)

我们常说Redis是单线程的是因为,Redis从接收请求到操作数据再到回复请求这个主要过程是有一个线程(主线程)完成的。

但是实际上Redis并不是单线程的,Redis有后台线程负责处理文件关闭,AOF刷盘,释放内存等耗时任务。

[Redis线程联想1]:Redis 采用单线程为什么还这么快?(经典追问)

有如下几个原因:

  • Redis 的大部分操作都在内存中完成,并且采用了高效的数据结构,因此 Redis 瓶颈可能是机器的内存或者网络带宽,而并非 CPU。(既然 CPU 不是瓶颈,那么自然就采用单线程的解决方案了)
  • Redis 采用单线程模型可以避免了多线程之间的竞争,省去了多线程切换带来的时间和性能上的开销,而且也不会导致死锁问题。
  • Redis 采用了 I/O 多路复用机制处理大量的客户端 Socket 请求,IO 多路复用机制是指一个线程处理多个 IO 流。(就是我们经常听到的 select/epoll 机制。简单来说,在 Redis 只运行单线程的情况下,该机制允许内核中,同时存在多个监听 Socket 和已连接 Socket。内核会一直监听这些 Socket 上的连接请求或数据请求。一旦有请求到达,就会交给 Redis 线程处理,这就实现了一个 Redis 线程处理多个 IO 流的效果。)

4.Redis持久化

Redis 如何实现数据不丢失?

为了保证内存中的数据不会丢失,Redis 实现了数据持久化的机制,这个机制会把数据存储到磁盘,这样在 Redis 重启就能够从磁盘中恢复原有的数据。

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

  • AOF 日志:每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里;
  • RDB 快照:将某一时刻的内存数据,以二进制的方式写入磁盘;
  • 混合持久化方式:Redis 4.0 新增的方式,集成了 AOF 和 RBD 的优点;

[持久化联想1]: AOF 日志是如何实现的?

Redis 执行完一条写操作命令,然把该命令以追加的方式写入到一个文件里,然后 Redis 重启时,会读取该文件记录的命令,然后逐一执行命令的方式来进行数据恢复。

追问:为什么先执行命令,再把数据写入日志呢?

答“如果先将写操作命令记录到 AOF 日志里,再执行该命令的话,如果当前的命令语法有问题,那么如果不进行命令语法检查,该错误的命令记录到 AOF 日志里后,Redis 在使用日志恢复数据时,就可能会出错。

再追问:先执行命令后写入日志有什么问题吗?

  • 数据可能会丢失: 执行写操作命令和记录日志是两个过程,那当 Redis 在还没来得及将命令写入到硬盘时,服务器发生宕机了,这个数据就会有丢失的风险。
  • 可能阻塞其他操作: 由于写操作命令执行成功后才记录到 AOF 日志,所以不会阻塞当前命令的执行,但因为 AOF 日志也是在主线程中执行,所以当 Redis 把日志文件写入磁盘的时候,还是会阻塞后续的操作无法执行。

[持久化联想2]:AOF 日志过大,会触发什么机制?

会出发aof重写机制,AOF中可能有不再有用的命令,AOF 重写机制是在重写时,读取当前数据库中的所有键值对,然后将每一个键值对用一条命令记录到「新的 AOF 文件」,等到全部记录完后,就将新的 AOF 文件替换掉现有的 AOF 文件。

追问:重写的过程中,主进程修改了已经存在的key-value怎么办?

答:如果主进程修改了已经存在 key-value,那么会发生写时复制,此时这个 key-value 数据在子进程的内存数据就跟主进程的内存数据不一致了,为了解决这种数据不一致问题,Redis 设置了一个 AOF 重写缓冲区,当 Redis 执行完一个写命令之后,它会同时将这个写命令写入到 「AOF 缓冲区」和 「AOF 重写缓冲区」。当子进程完成 AOF 重写工作后,会向主进程发送一条信号,主进程收到该信号后,会调用一个信号处理函数,该函数主要做以下工作:

  • 将 AOF 重写缓冲区中的所有内容追加到新的 AOF 的文件中,使得新旧两个 AOF 文件所保存的数据库状态一致;
  • 新的 AOF 的文件进行改名,覆盖现有的 AOF 文件。

[持久化联想3]:RDB 快照是如何实现的呢?

一旦 AOF 日志非常多,势必会造成 Redis 的恢复操作缓慢。为了解决这个问题,Redis 增加了 RDB 快照。RDB 快照就是记录某一个瞬间的内存数据,在 Redis 恢复数据时,直接将 RDB 文件读入内存就可以。

追问:RDB 在执行快照的时候,数据能修改吗?

答:不推荐,但是可以的,执行 bgsave 过程中,Redis 依然可以继续处理操作命令的,也就是数据是能被修改的,关键的技术就在于**写时复制技术(Copy-On-Write, COW)。**如果主线程执行写操作,则被修改的数据会复制一份副本,然后 bgsave 子进程会把该副本数据写入 RDB 文件,在这个过程中,主线程仍然可以直接修改原来的数据。会造成数据不一致,是要等下一轮持久化执行时再去同步,如果redis突然宕机,就是会导致丢失部分最新数据的。

[持久化联想4]:Redis采用的是哪种方式?/为什么会有混合持久化?

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

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

为了集成了两者的优点, Redis 4.0 提出了混合使用 AOF 日志和内存快照,也叫混合持久化,既保证了 Redis 重启速度,又降低数据丢失风险。混合持久化工作在 AOF 日志重写过程,当开启了混合持久化时,在 AOF 重写日志时,fork 出来的重写子进程会先将与主线程共享的内存数据以 RDB 方式写入到 AOF 文件,然后主线程处理的操作命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以 AOF 方式写入到 AOF 文件,写入完成后通知主进程将新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件。

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

追问:混合持久化有什么优缺点?

混合持久化优点:

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

混合持久化缺点:

  • AOF 文件中添加了 RDB 格式的内容,使得 AOF 文件的可读性变得很差;
  • 兼容性差,如果开启混合持久化,那么此混合持久化 AOF 文件,就不能用在 Redis 4.0 之前版本了。

5.Redis集群

Redis 如何实现服务高可用?

要想设计一个高可用的 Redis 服务,一定要从 Redis 的多服务节点来考虑,比如 Redis 的主从复制、哨兵模式、切片集群。

[集群联想1]:主从复制是什么?

主从复制是 Redis 高可用服务的最基础的保证,实现方案就是将从前的一台 Redis 服务器,同步数据到多台从 Redis 服务器上,即一主多从的模式,且主从服务器之间采用的是「读写分离」的方式。

主服务器可以进行读写操作,当发生写操作时自动将写操作同步给从服务器,而从服务器一般是只读,并接受主服务器同步过来写操作命令,然后执行这条命令。注意,主从服务器之间的命令复制是异步进行的。所以,无法实现强一致性保证(主从数据时时刻刻保持一致),数据不一致是难以避免的。

[集群联想2]:哨兵模式了解吗?

在使用 Redis 主从服务的时候,会有一个问题,就是当 Redis 的主从服务器出现故障宕机时,需要手动进行恢复。

为了解决这个问题,Redis 增加了哨兵模式(Redis Sentinel),因为哨兵模式做到了可以监控主从服务器,并且提供主从节点故障转移的功能。

[集群联想3]:切片集群模式?当 Redis 缓存数据量大到一台服务器无法缓存用什么模式?

当 Redis 缓存数据量大到一台服务器无法缓存时,就需要使用 Redis 切片集群(Redis Cluster )方案,它将数据分布在不同的服务器上,以此来降低系统对单主节点的依赖,从而提高 Redis 服务的读写性能。

Redis Cluster 方案采用哈希槽(Hash Slot),来处理数据和节点之间的映射关系。在 Redis Cluster 方案中,一个切片集群共有 16384 个哈希槽,这些哈希槽类似于数据分区,每个键值对都会根据它的 key,被映射到一个哈希槽中,具体执行过程分为两大步:

  • 根据键值对的 key,按照 CRC16 算法 (opens new window)计算一个 16 bit 的值。
  • 再用 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的哈希槽。

哈希槽被自动平均或手动分配映射到各Redis节点上。

[集群联想4]:集群脑裂知道吗?

在 Redis 主从架构中,部署方式一般是「一主多从」,主节点提供写操作,从节点提供读操作。 如果主节点的网络突然发生了问题,哨兵发现主节点失联了,它就认为主节点挂了(但实际上主节点正常运行,只是网络出问题了),于是哨兵就会在「从节点」中选举出一个 leader 作为主节点,这时集群就有两个主节点了 —— 脑裂出现了

等网络恢复,旧主节点会降级为从节点,再与新主节点进行同步复制的时候,由于会从节点会清空自己的缓冲区,所以导致之前客户端写入的数据丢失了。

追问:那脑裂问题怎么解决呢?

答:当主节点发现从节点总数量小于阈值或者通信超时,那么禁止主节点进行写数据,直接把错误返回给客户端。等到新主库上线时,就只有新主库能接收和处理客户端请求,此时,新写的数据会被直接写到新主库中。而原主库会被哨兵降为从库,即使它的数据被清空了,也不会有新数据丢失。

6.Redis过期删除与内存淘汰策略

7.Redis缓存

8.其他常问

标签:知识点,面试题,AOF,Redis,RDB,日志,数据,节点
From: https://blog.csdn.net/qq_45477639/article/details/139596093

相关文章

  • Redis之持久化
    Redis持久化Redis是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失。所以Redis提供了持久化功能!RDB(RedisDataBase)在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是Snapshot快照,它恢复时是将快照文件直接......
  • Redis在微服务架构中的角色:服务间通信与数据共享
    I.引言A.介绍微服务架构的概念和特点 微服务架构是一种设计模式,它将一个大型的单体应用分解成一组小的服务,每个服务都运行在其自身的进程中,独立地进行部署和扩展。这些服务之间通过轻量级的通信机制(如HTTPRESTfulAPI)进行交互,每个服务都围绕一个特定的业务功能进行组......
  • Redis的监控与调优:工具使用和性能提升技巧
    I.引言A.介绍Redis的重要性,以及为什么需要对Redis进行监控和调优 Redis是一种内存数据结构存储系统,它支持多种数据类型,如字符串、列表、集合、哈希表等,并提供了丰富的操作命令。Redis的高性能和灵活性使其在许多场景中都发挥了重要作用,例如,作为缓存降低数据库的访问压......
  • 浙大版PTA python程序设计 第四章题目及知识点解析整理
    第四章--1--在循环中continue语句的作用是(结束本次循环)退出循环的当前迭代  √ 带有else子句的循环如果因为执行了break语句而退出的话,会执行else子句的代码。×因为break是跳出整个循环,所以如果循环体内有else子句,且循环是通过break退出的,那么else子句中的代码也不......
  • redis-benchmark 基准测试
    我们可以通过redis自带工具redis-benchmark来对redis服务器进行性能测试。我们可以通过简单的redis-benchmark命令直接对本地部署的redis进行性能测试,不用输入任何的参数。默认情况下,redis-benchmark会向redis服务器使用50个并发连接发送共100000个请求。......
  • 公式面试题总结(三)
    13.说说你对BOM的理解,常见的BOM对象你了解哪些?BOM(BrowserObjectModel),浏览器对象模型,⚫提供了独立于内容与浏览器窗口进行交互的对象⚫其作用就是跟浏览器做一些交互效果⚫比如如何进行页面的后退,前进,刷新,浏览器的窗口发生变化,滚动条的滚动,以及......
  • 运维系列:redis.conf“ E212: 无法打开并写入文件
    redis.conf"E212:无法打开并写入文件redis.conf"E212:无法打开并写入文件Redis配置文件的E212错误解决方法介绍E212错误的原因E212错误表示无法打开并写入文件,这通常是由于以下几个原因造成的:解决方法1.权限问题2.文件不存在3.文件被锁定4.重启Redis服务流程图......
  • C&C++内存管理【new和delete操作符的详细分析】【常见面试题】
    C/C++内存管理1.C/C++内存分布我们先来看一段代码,来了解一下C/C++中的数据内存分布。#include<stdlib.h>intglobalVar=1;staticintstaticGlobalVar=1;//比globalVar还要先销毁,同一个文件下后定义的先析构//全局变量存在数据段(静态区)但是链接方式和静......
  • Redis 面试热点(一)
    Redis是一个高性能的内存数据库,广泛应用于缓存、会话管理、实时数据分析等场景。掌握Redis的常见问题和高级用法对于面试非常有帮助。本文将介绍5个Redis面试热点,帮助你在面试中脱颖而出。1.Redis数据类型及其应用场景常见数据类型String(字符串):最基本的类型,可......
  • 【Redis】Redis实现高性能的原因
    Redis作为一个单线程的数据库,能够达到高性能的关键在于其设计上的几个方面。以下是Redis快速的几个主要原因:1.内存存储Redis是一个内存数据库,所有数据都存储在内存中。内存的访问速度远远快于磁盘,所以这使得读写操作非常快速。2.简单的数据结构Redis提供了一些基......