zoukankan      html  css  js  c++  java
  • Redis面试题面经整理+解析

    前言

    本文主要是针对Redis的高频知识点整理出来的面试题,答案大部分参考网上,仅供复习参考。本文中如果出现解答错误希望指出,共同进步,共同学习。

    正文

    Q1:你了解Redis,能介绍一下Redis吗?

    Redis(全称:Remote Dictionary Server 远程字典服务)是一个开源的使用ANSIC语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,遵守BSD协议。是一个非关系型数据库(NoSQL)。


    Q2:Redis与其他数据库有什么很大的优势吗?

    1. 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
    2. 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
    3. 事务 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,但是不保证原子性,即失败了的不影响其他成功的。通过MULTI和EXEC指令包起来。
    4. 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。

    Q3:Redis也有事务吗?能不能说一下Redis的事务?

    Redis的事务本质就是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。Redis单个命令保证原子性,一个事务里面多个命令就不保证了,即有成功有失败。

    Redis的事务只要分为三个阶段:开始事务,命令入队,执行事务。期间可以使用watch指令来对变量进行监控,watch类似乐观锁,如果watch监控的多个KEY中任何KEY的值已经被其他客户端更改,则使用EXEC执行事务时,事务队列将不会被执行,同时返回Nullmulti-bulk应答以通知调用者事务执行失败。


    Q4:Redis有丰富的特性,那么特性有哪些?

    速度快;简单稳定; 支持多种数据结构;支持多种编程语言;功能丰富;持久化;主从复制;高可用和分布式。好了,下面的问题基本也是围绕这八个特性来问的。


    Q5:Redis为什么速度那么快?

    总结一句:Redis 使用了单线程架构和 IO 多路复用模型来实现高性能的内存数据库服务。

    扩展开来:① Redis使用纯内存访问,将所有数据放在内存中。② 非阻塞 IO,Redis 使用 epoll 作为 IO 多路复用技术的实现,再加上 Redis 本身的事件处理模型将 epoll 中的连接、读写、关闭都转换为事件,不在网络 IO 上浪费过多的时间。③ 单线程避免了线程切换和竞争产生的消耗。单线程的一个问题是对于每个命令的执行时间是有要求的,如果某个命令执行时间过长会造成其他命令的阻塞,对于 Redis 这种高性能服务来说是致命的,因此 Redis 是面向快速执行场景的数据库。

    补充:Redis的单线程指的是网络请求模块使用了一个线程(所以不需考虑并发安全性),即一个线程处理所有网络请求,其他模块仍用了多个线程。


    Q6:为什么说Redis简单稳定呢?是因为单线程吗?

    与单线程是有一定的关系的。之所以说Redis简单稳定,主要是有三个方面的原因:

    ① 源码很少,早期只有 2 万行左右,在 3.0 版本由于添加了集群特性,增加到了 5 万行左右,相对于很多 NoSQL 数据库来说代码量要少很多。

    ② 采用单线程模型,使得服务端处理模型更简单,也使客户端开发更简单。

    ③ 不依赖底层操作系统的类库,自己实现了事件处理的相关功能。


    Q7:说一下Redis支持哪些数据类型,分别可以运用到什么场景?


    Q8:Redis功能丰富,那么提供了哪些简单的功能?

    ① 提供了键过期功能,可以实现缓存。

    ② 提供了发布订阅功能,可以实现消息系统。

    ③ 支持 Lua 脚本,可以创造新的 Redis 命令。

    ④ 提供了简单的事务功能,能在一定程度上保证事务特性。

    ⑤ 提供了流水线功能,客户端能将一批命令一次性传到 Redis,减少网络开销。


    Q9:Redis是怎么进行持久化?

    我们知道Redis的数据都存在内存里,如果突然宕机,数据就会全部丢失,因此必须有一种机制来保证Redis的数据不会因为故障而丢失,这种机制就是Redis的持久化机制。

    Redis的持久化机制主要是有两种,第一种是RDB快照,第二种是AOF日志。如果我们的服务器开启了AOF持久化功能,那么服务器会优先使用AOF文件来还原数据库的状态。只有在AOF持久化功能处于关闭的状态的时候,服务器才能使用RDB文件来还原数据库状态。


    Q10:能说一下RDB持久化的原理吗?

    RDB持久化是通过快照来实现的,在指定的时间间隔内将内存的数据集快照写入磁盘,恢复的时候就是将快照文件读取到内存中。

    (1)一般手动触发可以使用save和bgsave命令:

    save:阻塞当前 Redis 服务器,直到 RDB 过程完成为止,对于内存比较大的实例会造成长时间阻塞,不建议使用。

    bgasve:Redis 进程执行 fork 操作创建子进程,RDB 持久化过程由子进程负责,完成后自动结束。阻塞只发生在 fork 阶段,一般时间很短。bgsave 是针对 save 阻塞问题做的优化,因此 Redis 内部所有涉及 RDB 的操作都采用 bgsave 的方式,而 save 方式已经废弃。所以RDB持久化主要原理要从bgsave这个命令来讲。(见下一题)

    (补充:可能会问到为什么需要fork一个子进程?这是因为Redis是单线程的,内存快照又要要求Redis进行文件IO操作。所以我们fork一个子进程就可以保证Redis主进程不进行IO操作,可以更好的保持极高的性能。)

    (2)而其他一些通过其他命令也会被动触发RDB持久化的也有:

    FLUSHALL:清空命令也会触发持久化操作,但dump.rdb文件中是空的,无意义;

    SHUTDOWN :关闭数据库命令也会触发redis持久化操作 ,前提是没有开启AOF持久化;

    DEBUG RELAOD:用该命令重新加载Redis时,也会自动触发save操作;

    (3)然后还有就是通过配置文件配置redis.conf文件中可以设置save。


    Q11:那能讲一下bgsave具体的工作流程吗?

    ① 执行 bgsave 命令,Redis 父进程判断当前是否存在正在执行的子进程,如 RDB/AOF 子进程,如果存在 bgsave 命令直接返回。

    ② 父进程执行 fork 操作创建子进程,fork 操作过程中父进程会阻塞。

    ③ 父进程 fork 完成后,bgsave 命令返回并不再阻塞父进程,可以继续响应其他命令。

    ④ 子进程创建 RDB 文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。

    ⑤ 进程发送信号给父进程表示完成,父进程更新统计信息。

    在这里详细说一下第三个步骤里面父进程fork一个子进程之后父进程还要持续服务端的请求。然后对内存数据结构进行不间断的修改。那我们不可能对同一片内存进行操作,所以用到了写入时复制(copy on write机制)。在父进程需要后续再写指令的时候,复制一个内存页面处理新的写请求,而子进程的页面是没有变化的,所以这也被称为快照的原因。

    img


    Q12:说了挺多你能总结一下RDB到底有什么优缺点?

    优点:

    • 对数据的完整性要求不高
    • 因为主进程不进行任何的IO操作,所以对数据的大规模恢复有着极高的性能,适合全量恢复 ,备份等场景

    缺点:

    • fork进程的时候,会占用一定的内存空间
    • 需要一定的时间间隔来进行操作,如果redis意外宕机了,那么最后一次修改的数据就没有了

    Q13:能说一下AOF持久化的原理吗?

    AOF 持久化以独立日志的方式记录每次写命令,重启时再重新执行 AOF 文件中的命令达到恢复数据的目的。AOF 的主要作用是解决了数据持久化的实时性,目前是 Redis 持久化的主流方式。

    默认是不开启AOF的,如果开启了,则优先使用AOF!

    AOF的具体工作流程如下:

    1. 命令的实时写入,调用到命令
    2. 所有的写入命令追加到aof_buf(缓冲区)中
    3. AOF缓冲区根据对应的策略向硬盘做同步操作
    4. 随着AOF文件越来越大,需要定期对AOF文件进行重写,压缩,父进程执行fork创建子进程,由子进程根据内存快照执行AOF重写,父进行继续响应后面的命令并写入aof_rewrite_buf(重写缓冲区),在子进程完成重写后,重写缓冲区再把新增的写入命令写入到新的AOF文件中。(注意,父进程原本的任务是没有终止的,还是会进行原来而AOF文件的写入同步)
    5. Redis服务重启,加载AOF文件进行数据恢复

    img

    主动触发可以使用bgrewriteaof命令,被动触发需要修改配置文件两个参数auto-aof-rewrite-min-sizeauto-aof-rewrite-percentage 来确定自动触发时机。


    Q14:AOF缓冲区,和AOF重写缓冲区,两者有什么区别?而且缓冲区有哪些对硬盘操作的同步的策略?

    aof缓冲区:是正常使用aof作为数据落地中间地带,所有的数据先到aof缓冲区再到aof文件中。

    aof重写缓冲区:是aof触发重写机制时,redis还要继续接收数据,这个数据就写到aof重写缓冲区,当aof重写ok时,主进程在把aof重写缓冲区的数据写到新的aof文件,然后替换原来的。

    aof缓冲区同步策略,通过参数appendfsync控制,具体有三个配值

    选项的值 说明 其他
    always 命令写入aof_buf后调用系统fsync操作同步到AOF文件,fsync完成后线程返回 每次写入都要同步AOF文件,在一般的SATA硬盘很难达到高性能
    everysec 命令写入aof_buf后调用系统write操作,write完成后线程返回。fsync同步操作由线程每秒调用一次(建议策略) 默认同步策略
    no 命令写入aof_buf后调用系统write操作,不对AOF文件做fsync同步,同步硬盘操作由操作系统负责,通常同步周期最长30秒 操作系统每次同步AOF文件的周期不可控,而且会加大每次同步硬盘的数据量,虽然提升了性能,但数据安全性无法保证

    Q15:说了这么多重写机制,那为什们重写就可以把我们的AOF文件变小?

    • 重写的时候,进程内已经超时的数据不再写入文件
    • 旧的AOF文件含有无效命令,重写使用进程内数据直接生成,新的AOF文件只保留最终数据的写入命令
    • 多条写命令可以合并为一个,为了防止溢出,以64个元素为界拆分为多条

    待更新

  • 相关阅读:
    Oracle trunc()函数的用法
    Python获取指定目录下文件名,及创建目录
    python复制文件并重命名
    python自动创建Excel,且文件名和内容从另一个Excel中自动获取
    pip命令提示unknow or unsupported command install解决方法及查看包方法
    今日份学习性能测试工具、瀑布图
    Oracle的NVL函数用法
    创建虚拟机过程
    Linux中使用 alias 来简化测试部分工作
    排序-冒泡-java
  • 原文地址:https://www.cnblogs.com/CryFace/p/13498188.html
Copyright © 2011-2022 走看看