Redis面试(一)

文章参考:全网最硬核 Redis 高频面试题解析(2021年最新版)

我的另一篇博客:Redis由浅到深层次讲解和springboot实战(服务器层面的搭建部署)_帆浆的博客-CSDN博客

1、Redis 是单线程还是多线程的?

  • redis 4.0 之前,redis 是完全单线程的

  • redis 4.0 时,redis 引入了多线程,但是额外的线程只是用于后台处理,例如:删除对象,核心流程还是完全单线程的。(核心流程指的是 redis 正常处理客户端请求的流程,通常包括:接收命令、解析命令、执行命令、返回结果等。)

  • redis 6.0 中,多线程主要用于网络 I/O 阶段,也就是接收命令和写回结果阶段,而在执行命令阶段,还是由单线程串行执行。

为什么 Redis 是单线程?

在 redis 6.0 之前,redis 的核心操作是单线程的。因为 redis 是完全基于内存操作的,通常情况下CPU不会是redis的瓶颈,redis 的瓶颈最有可能是机器内存的大小或者网络带宽。

既然CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了,因为如果使用多线程的话会更复杂,同时需要引入上下文切换、加锁等等,会带来额外的性能消耗

Redis 为什么使用单进程、单线程也很快?

主要有以下几点:

1、Redis 基于内存的操作

2、Redis 使用了 I/O 多路复用模型,select、epoll 等,基于 reactor 模式开发了自己的网络事件处理器

3、单线程可以避免不必要的上下文切换和竞争条件,减少了这方面的性能消耗。

2、Redis 在项目中的使用场景

缓存(核心)、分布式锁(set + lua 脚本)、排行榜(zset)、计数(incrby)、消息队列(stream)、地理位置(geo)、访客统计(hyperloglog)等。

3、Redis 常见的数据结构

基础的5种:

  • String:字符串,最基础的数据类型。
  • List:列表。
  • Hash: 哈希对象。
  • Set: 集合。
  • Sorted Set:有序集合,Set 的基础上加了个分值。

高级的4种:

  • HyperLogLog: 通常用于基数统计(例如,网站访客统计)。
  • BigMap: 位图。
  • ego: redis 3.2 版本的新特性。可以将用户给定的地理位置信息储存起来, 并对这些信息进行操作:获取2个位置的距离、根据给定地理位置坐标获取指定范围内的地理位置集合。
  • Stream: 主要用于消息队列,类似于 kafka,可以认为是 pub/sub 的改进版。提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。

4、Redis 删除过期键的策略(缓存失效策略、数据过期策略)

  • 定时删除:在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作。对内存最友好,对 CPU 时间最不友好。
  • 惰性删除:放任键过期不管,但是每次获取键时,都检査键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。对 CPU 时间最优化,对内存最不友好。
  • 定期删除:每隔一段时间,默认 100ms,程序就对数据库进行一次检査,删除里面的过期键。至 于要删除多少过期键,以及要检査多少个数据库,则由算法决定。前两种策略的折中,对 CPU 时间和内存的友好程度较平衡

Redis 使用惰性删除和定期删除。

5、Redis 的内存淘汰(驱逐)策略

当 redis 的内存空间(maxmemory 参数配置)已经用满时,redis 将根据配置的驱逐策略(maxmemory-policy 参数配置),进行相应的淘汰动作。

  • noeviction:默认策略,不淘汰任何 key,直接返回错误。
  • allkeys-lru:在所有的 key 中,使用 LRU 算法淘汰部分 key。
  • allkeys-lfu:在所有的 key 中,使用 LFU 算法淘汰部分 key,该算法于 Redis 4.0 新增。
  • allkeys-random:在所有的 key 中,随机淘汰部分 key。
  • volatile-lru:在设置了过期时间的 key 中,使用 LRU 算法淘汰部分 key。
  • volatile-lfu:在设置了过期时间的 key 中,使用 LFU 算法淘汰部分 key,该算法于 Redis 4.0 新增。
  • volatile-random:在设置了过期时间的 key 中,随机淘汰部分 key。
  • volatile-ttl:在设置了过期时间的 key 中,挑选 TTL(time to live,剩余时间)短的 key 淘汰。

6、淘汰算法

  • FIFO:First In First Out,先进先出。新访问的数据插入 FIFO 队列尾部,数据在 FIFO 队列中顺序移动,淘汰 FIFO 队列头部的数据。

  • LRU:Least Recently Used,最近最少使用。判断最近被使用的时间,目前最远的数据优先被淘汰。

    • 新数据插入到链表头部,每当缓存数据被访问,则将数据移到链表头部,当链表满的时候,将链表尾部的数据丢弃
  • LFU:Least Frequently Used,最不经常使用。在一段时间内,数据被使用次数最少的,优先被淘汰。

    • 把数据加入到链表中,按频次排序,一个数据被访问过,把它的频次+1,发生淘汰的时候,把频次低的淘汰掉

7、Redis 的持久化机制有哪几种,各自的实现原理和优缺点?

Redis 的持久化机制有:RDB、AOF、混合持久化(RDB+AOF,Redis 4.0 引入)。

① RDB(Redis DataBase)

在指定时间间隔后,将内存中的数据集快照写入数据库 ;在恢复时候,直接读取快照文件,进行数据的恢复 ;
默认情况下, Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中。文件名可以在配置文件中进行自定义。

简单来说就是将内容中的数据进行备份写入到文件(dump.rdb 里面存放的是直接的数据),恢复时直接使用里面的数据来进行数据的恢复。

特点:

  • 速度快
  • 所占空间小
  • 性能好
  • 可能会丢失最后一次更新的数据
  • 描述:类似于快照。在指定的时间间隔内将内存中的数据集快照写入磁盘,可以指定时间归档数据,但不能做到实时持久化,RDB 持久化功能生成的 RDB 文件是经过压缩的二进制文件
  • 命令:有两个 Redis 命令可以用于生成 RDB 文件,一个是SAVE,另一个是 BGSAVE
  • 开启:使用 save point 配置,满足 save point 条件后会触发 BGSAVE 来存储一次快照,这边的 save point 检查就是在上文提到的 serverCron 中进行。

save point 格式:save <seconds> <changes>,含义是 Redis 如果在 seconds 秒内数据发生了 changes 次改变,就保存快照文件。例如 Redis 默认就配置了以下3个:

save 900 1 # 900秒内有1个key发生了变化,则触发保存RDB文件
save 300 10 # 300秒内有10个key发生了变化,则触发保存RDB文件
save 60 10000 # 60秒内有10000个key发生了变化,则触发保存RDB文件
  • 关闭
    • 1)注释掉所有save point 配置可以关闭 RDB 持久化。
    • 2)在所有 save point 配置后增加:save “”,该配置可以删除所有之前配置的 save point。
save ""
  • SAVE:生成 RDB 快照文件,但是会阻塞主进程,服务器将无法处理客户端发来的命令请求,所以通常不会直接使用该命令。
  • BGSAVE:fork 子进程来生成 RDB 快照文件,阻塞只会发生在 fork 子进程的时候,之后主进程可以正常处理请求。

RDB 的优点:

  • RDB 文件是是经过压缩的二进制文件,占用空间很小,它保存了 Redis 某个时间点的数据集,很适合用于做备份。

  • RDB 在恢复大数据集时的速度比 AOF 的==恢复速度要快==。

  • RDB 可以==最大化 redis 的性能==。父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作父进程无须执行任何磁盘 I/O 操作

RDB 的缺点

  • RDB 在服务器故障时容易造成数据的丢失。RDB 允许我们通过修改 save point 配置来控制持久化的频率。但是,因为 RDB 文件需要保存整个数据集的状态, 所以它是一个比较重的操作,如果频率太频繁,可能会对 Redis 性能产生影响。所以通常可能设置至少5分钟才保存一次快照,这时如果 Redis 出现宕机等情况,则意味着最多可能丢失5分钟数据。
  • RDB 保存时使用 fork 子进程进行数据的持久化,如果数据比较大的话,fork 可能会非常耗时,造成 Redis 停止处理服务 N 毫秒。如果数据集很大且 CPU 比较繁忙的时候,停止服务的时间甚至会到一秒。

② AOF (Append Only File)

以日志的形式来记录每个写的操作,将Redis执行过的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。

简单来说就是,将我们所有的命令都记录下来,history,恢复的时候就把这个文件全部再执行一遍

特点:

  • 不需要同步,效率高
  • 每一次的修改都会被记录,文件的完整性更好
  • 文件大,需要记录每一次的操作指令
  • 描述:以日志的形式记录服务器所处理的每一个写、删除操作(查询操作不会记录),以文本的方式记录,并在服务器启动时,通过重新执行这些命令来还原数据集。
  • 开启:AOF 持久化默认是关闭的,可以通过配置:appendonly yes 开启。
  • 关闭:使用配置 appendonly no 可以关闭 AOF 持久化。

AOF 的优点

  • AOF 比 RDB可靠,支持秒级持久化,就算发生故障停机,也最多只会丢失一秒钟的数据。
  • 当 AOF文件太大时,Redis 会自动在后台进行重写:重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。当新文件重写完毕,Redis 会把新旧文件进行切换,然后开始把数据写到新文件上。

AOF 的缺点

  • 对于相同的数据集,AOF 文件的大小一般会比 RDB 文件大。
  • RDB 存储的是压缩二进制格式记录数据命令,AOF 是通过文本日志形式记录数据命令,所以采用 AOF 数据恢复比 RDB 慢。

③ 混合持久化

  • 描述:混合持久化并不是一种全新的持久化方式,而是对已有方式的优化。混合持久化只发生于 AOF 重写过程。使用了混合持久化,重写后的新 AOF 文件前半段是 RDB 格式的全量数据,后半段是 AOF 格式的增量数据。
  • 优点:结合 RDB 和 AOF 的优点, 更快的重写和恢复。

8、为什么需要 AOF 重写文件?

  • AOF 持久化是通过保存被执行的写命令来记录数据库状态的,随着写入命令的不断增加,AOF 文件中的内容会越来越多,文件的体积也会越来越大。
  • 如果不加以控制,体积过大的 AOF 文件可能会对 Redis 服务器、甚至整个宿主机造成影响,并且 AOF 文件的体积越大,使用 AOF 文件来进行数据还原所需的时间就越多。

举个例子, 如果你对一个计数器调用了 100 次 INCR , 那么仅仅是为了保存这个计数器的当前值, AOF 文件就需要使用 100 条记录。然而在实际上, 只使用一条 SET 命令已经足以保存计数器的当前值了, 其余 99 条记录实际上都是多余的。

为了处理这种情况, Redis 引入了 AOF 重写:可以在不打断服务端处理请求的情况下, 对 AOF 文件进行重建(rebuild)。

9、介绍下 AOF 重写的过程、AOF 后台重写存在的问题、如何解决 AOF 后台重写存在的数据不一致问题

AOF 后台重写存在的问题

AOF 后台重写使用子进程进行从写,解决了主进程阻塞的问题,但是仍然存在另一个问题:子进程在进行 AOF 重写期间服务器主进程还需要继续处理命令请求,新的命令可能会对现有的数据库状态进行修改,从而使得当前的数据库状态和重写后的 AOF 文件保存的数据库状态不一致

如何解决 AOF 后台重写存在的数据不一致问题

为了解决上述问题,Redis 引入了 AOF 重写缓冲区(aof_rewrite_buf_blocks),这个缓冲区在服务器创建子进程之后开始使用,当 Redis 服务器执行完一个写命令之后,它会同时将这个写命令追加到 AOF 缓冲区和 AOF 重写缓冲区

这样一来可以保证:

  • 1、现有 AOF 文件的处理工作会如常进行。这样即使在重写的中途发生停机,现有的 AOF 文件也还是安全的。
  • 2、从创建子进程开始,也就是 AOF 重写开始,服务器执行的所有写命令会被记录到 AOF 重写缓冲区里面。

这样,当子进程完成 AOF 重写工作后,父进程会在 serverCron 中检测到子进程已经重写结束,则会执行以下工作:

  • 1、将 AOF 重写缓冲区中的所有内容写入到新 AOF 文件中,这时新 AOF 文件所保存的数据库状态将和服务器当前的数据库状态一致。
  • 2、对新的 AOF 文件进行改名,原子的覆盖现有的 AOF 文件,完成新旧两个 AOF 文件的替换。

之后,父进程就可以继续像往常一样接受命令请求了。

10、同时开启RDB和AOF,服务重启时如何加载

简单来说,如果同时启用了 AOF 和 RDB,Redis 重新启动时,会先使用 AOF 文件来重建数据集,因为通常来说, AOF 的数据会更完整。

而在引入了混合持久化之后,使用 AOF 重建数据集时,会通过文件开头是否为“REDIS”来判断是否为混合持久化。

完整流程如下图所示:

在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三横同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值