面试必备Redis知识 -- Redis面试题(一)

x33g5p2x  于2022-03-09 转载在 Redis  
字(5.8k)|赞(0)|评价(0)|浏览(395)

📒博客首页:崇尚学技术的科班人
🍣今天给大家带来的文章是《面试必备Redis知识 -- Redis面试题(一)》🍣
🍣希望各位小伙伴们能够耐心的读完这篇文章🍣
🙏博主也在学习阶段,如若发现问题,请告知,非常感谢🙏
💗同时也非常感谢各位小伙伴们的支持💗

1、简单说一下 redis 是什么?

👨‍💻**:简单说一下 redis 是什么。**

  1. Redis 就是一个使用 C 语言开发的数据库
  2. Redis 的数据是存在内存中的 ,也就是它是内存数据库,所以读写速度非常快,因此 Redis 被广泛应用于缓存方向。
  3. Redis 除了做缓存之外,也经常用来做分布式锁,甚至是消息队列
  4. Redis 提供了多种数据类型来支持不同的业务场景。Redis 还支持事务 、持久化、Lua 脚本、多种集群方案

2、 比较一下 redis 和 memcached 的共同点和不同点

👨‍💻**:比较一下 redis 和 memcached 。**

1)、共同点

  1. 都是基于内存的数据库,一般都用来当做缓存使用。
  2. 都有过期策略。
  3. 两者的性能都非常高。

2)、不同点

  1. Redis 支持更丰富的数据类型(支持更复杂的应用场景)。Redis 不仅仅支持简单的 k/v 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储。Memcached 只支持最简单的 k/v 数据类型。
  2. Redis 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而 Memcached 把数据全部存在内存之中。
  3. Redis 有灾难恢复机制。正因为 Redis 可以将数据持久化到磁盘中,所以 Redis 就具有了灾难恢复机制。
  4. Redis 在服务器内存使用完之后,可以将不用的数据放到磁盘上。 但是,Memcached 在服务器内存使用完之后,就会直接报异常
  5. Memcached 过期数据的删除策略只用了惰性删除,而 Redis 同时使用了惰性删除与定期删除。
  6. Memcached 是多线程,非阻塞 IO 复用的网络模型;Redis 使用单线程的多路 IO 复用模型。
  7. Memcached 没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据;但是 Redis 目前是原生支持 cluster 模式的
  8. Redis 支持发布订阅模型、Lua 脚本、事务等功能,而 Memcached 不支持。 并且,Redis 支持更多的编程语言。

3、为什么要使用 Redis ?

👨‍💻**:听说你在项目中使用到了 redis,说一说你为什么要使用 redis ?**

  • 我们来简要分析一下:首先面试官说了你在项目中使用到了 redis ,那么你就要结合你的项目进行回答一下你使用 redis 的带来的优化,由于这里涉及到各位小伙伴们自己的项目了,那么我们就不进行展开了有各位小伙伴们自己发挥。这里我们统一说一说 redis 的优点
  1. 在项目中我们使用了 Redis 作缓存,Redis 的数据是存在内存中的 ,也就是它是内存数据库,所以读写速度非常快。而 MySQL 数据库是将数据存储在磁盘中的,所以查询速度十分缓慢,我们可以将长时间访问的且不经常变化的数据存储在 Redis 中,从而提升了系统的性能。只是,当我们对涉及到缓存中的内容修改的时候,我们需要将缓存失效。进而保持数据的一致性。
  • 除了上述所说,在接触到了 Redis 之后,我还发现了 Redis 的其它优点。
  1. 丰富的数据类型 – Redis 支持二进制案例的 Strings、 Lists、Hashes、Sets 及 Ordered Sets 数据类型操作。
  2. 原子 – Redis 的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI 和 EXEC 指令包起来。
  3. 丰富的特性 – Redis 还支持 publish/subscribe, 通知, key 过期等特性。

4、Redis 的应用场景

👨‍💻**:redis有哪些应用场景 ?**

  1. 缓存

优化查询性能,减轻 MySQL 压力,提升系统整体性能。

  1. 排行榜

利用Redis的 SortSet (有序集合)实现

  • 计数器/限速

  • 利用Redis 中原子性的自增操作,我们可以统计类似用户点赞数、用户访问数等。

  • 限速器比较典型的使用场景是限制某个用户访问某个API的频率,常用的有抢购时,防止用户疯狂点击带来不必要的压力

  • 好友关系

利用集合的一些命令,比如求交集、并集、差集等。可以方便解决一些共同好友、共同爱好之类的功能

  1. 消息队列

可以使用 Stream 数据结构进行实现,还有其自身所携带的 发布/订阅模式

  1. 分布式锁

set + lua 脚本。

  1. session共享

session 是保存在服务器的文件中,如果是集群服务,同一个用户过来可能落在不同机器上,这就会导致用户频繁登陆。采用 Redis 保存 Session 后,从 Redis 中查询获取 session 信息,无论用户落在那台机器上都能够获取到对应的 Session 信息。

5、Redis 常见的数据结构

👨‍💻**:redis常见的数据结构有哪些 ?**

数据结构介绍常用命令应用场景
stringredis 构建了一种 简单动态字符串(SDS),Redis 的 SDS 不光可以保存文本数据还可以保存二进制数据,并且获取字符串长度复杂度为 O(1)(C 字符串为 O(N)),除此之外,Redis 的 SDS API 是安全的,不会造成缓冲区溢出set,get,strlen,exists,decr,incr,setex一般常用在需要计数的场景,比如用户的访问次数、热点文章的点赞转发数量等
listRedis 的 list 的实现为一个 双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销。rpush,lpop,lpush,rpop,lrange,llen发布与订阅或者说消息队列、慢查询。
hashhash 是一个 string 类型的 field 和 value 的映射表,内部实现也差不多(数组 + 链表)。hset,hmset,hexists,hget,hgetall,hkeys,hvals系统中对象数据的存储
setRedis 中的 set 类型是一种无序集合,集合中的元素没有先后顺序,同时也不会出现重复数据sadd,spop,smembers,sismember,scard,sinterstore,sunion需要存放的数据不能重复以及需要获取多个数据源交集和并集等场景
sorted setsorted set 增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列,还可以通过 score 的范围来获取元素的列表。zadd,zcard,zscore,zrange,zrevrange,zrem需要对数据根据某个权重进行排序的场景。比如在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为按消息维度的消息排行榜)等信息。

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

👨‍💻**:redis 是单线程还是多线程的?**

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

  2. redis 4.0 时,redis 引入了多线程,但是额外的线程只是用于后台处理。删除对象的时候,核心线程还是单线程的。

  3. redis 6.0 中,多线程主要用于网络 I/O 阶段
    👨‍💻追问道:redis 为什么是单线程的?

  4. 单线程编程容易并且更容易维护

  5. Redis 的性能瓶颈不在 CPU ,主要在内存和网络

  6. 多线程就会存在死锁、线程上下文切换等问题,甚至会影响性能。
    👨‍💻追问道:redis 为什么在 6.0 的时候又引入多线程呢 ?

  7. Redis6.0 引入多线程主要是为了提高网络 IO 读写性能,因为这个算是 Redis 中的一个性能瓶颈(Redis 的瓶颈主要受限于内存和网络)。

  8. 但是 Redis 的多线程只是在网络数据的读写这类耗时操作上使用了,执行命令仍然是单线程顺序执行

7、Redis 过期的 key 删除策略

👨‍💻**:redis 过期的 key 删除策略你了解吗?**

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

8、Redis 内存淘汰机制

👨‍💻**:redis 内存淘汰机制你了解吗?**

  • Redis 提供 6 种数据淘汰策略:
  1. volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
  2. volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰
  3. volatile-random:从已设置过期时间的数据集中任意选择数据淘汰
  4. allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)
  5. allkeys-random:从数据集中任意选择数据淘汰
  6. no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!
  • 4.0 版本后增加以下两种:
  1. volatile-lfu:从已设置过期时间的数据集中挑选最不经常使用的数据淘汰
  2. allkeys-lfu:当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的 key

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

👨‍💻**:redis 的几种持久化机制你了解过吗?说一说各自的实现原理和优缺点呗**

① RDB

  • 描述:类似于快照。在指定的时间间隔内将内存中的数据集快照写入磁盘,可以指定时间归档数据,但不能做到实时持久化,RDB 持久化功能生成的 RDB 文件是经过压缩的二进制文件。
  • 间隔时间配置
save 900 1           #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

save 300 10          #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

save 60 10000        #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

RDB的优点

  1. RDB 文件是是经过压缩的二进制文件,占用空间很小

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

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

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

② AOF

  • 描述:以日志的形式记录服务器所处理的每一个写、删除操作(查询操作不会记录),以文本的方式记录,并在服务器启动时,通过重新执行这些命令来还原数据集。
  • 配置文件配置
appendfsync always    #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
appendfsync everysec  #每秒钟同步一次,显式地将多个写命令同步到硬盘
appendfsync no        #让操作系统决定何时进行同步

AOF的优点

  1. AOF 比 RDB可靠,支持秒级持久化,就算发生故障停机,也最多只会丢失一秒钟的数据。

  2. 当 AOF文件太大时,Redis 会自动在后台进行重写:重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。当新文件重写完毕,Redis 会把新旧文件进行切换,然后开始把数据写到新文件上。
    AOF的缺点

  3. 对于相同的数据集,AOF 文件的大小一般会比 RDB 文件大。

  4. RDB 存储的是压缩二进制格式记录数据命令,AOF 是通过文本日志形式记录数据命令,所以采用 AOF 数据恢复比 RDB 慢

③ 混合持久化

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

10、为什么要重写 AOF 文件?

👨‍💻**:redis 为什么要重写 AOF 文件?**

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

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

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

👨‍💻**:介绍一下AOF 后台重写存在的问题、如何解决 AOF 后台重写存在的数据不一致问题?**

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

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

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

父进程检测到相关的子进程完成相关的重写工作之后,会进行以下操作:

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

相关文章