面试必问—Redis持久化机制(建议收藏)

  • 本次分享的是本人最近阅读《Redis设计与实现》的总结。Redis持久化这块在面试中还是比较常问的,希望对大家有帮助。有问题欢迎评论区指出。
  • 由于Redis是内存数据库,所以它自己的数据库的状态是存储在内存里面的,不同于存储与磁盘的数据库。在日常的生产中,一旦出现服务器进程退出的情况,服务器中的数据库的状态也会消失。所以,为了避免这种意外的发生,Redis有一套自己的持久化机制。
  • Redis的持久化机制分为RDB持久化和AOF持久化。

RDB持久化

  • RDB持久化可以让数据库可以恢复到某一个时间点。它保存的数据是经过压缩的二进制数据。大概下面这种的
    alt

  • 创建和载入

    • RDB文件的创建主要有SAVE命令和BGSAVE命令

    • SAVE命令会阻塞Redis服务器进程,在这段期间,服务器一直在创建RDB文件,对于这个期间内的任何的命令都不会执行。

    • BGSAVE命令会创建一个子进程来专门创建RDB文件。

    • RDB文件的载入在服务启动的时候就会检测这个RDB文件是否存在,如果存在就会写入到我们创建好的RDB文件里面。

    • SAVE命令会阻塞服务器,所以其实在日常的生产中用得比较少,下面我们主要来介绍一下BGSAVE命令

    • redisServer的结构

        struct redisServer {
          struct saveparam *saveparam;
          long long dirty;
          time_t lastsave;
        }

      alt

      • saveparam是一个记录保存条件的数组,里面有两个参数seconds和changes。save seconds changes的意思是服务器在seconds(s)内对数据库至少进行了changes次操作就会触发一次BGSAVE。
      • dirty是记录了距离上一次成功SAVE或者是BGSAVE,对数据库进行了多少次修改。(增,删,改,查等操作)
      • lastsave是记录了上一次保存的时间,是一个UNIX时间戳。
      • BGSAVE命令是非阻塞的,所以Redis为我们提供了定时进行BGSAVE的方法来创建新的RDB文件。默认的是
        save 900 1
        save 300 10
        save 60 10000
    • Redis的服务器有一个周期性的操作函数serverCorn,会每隔100ms去判断是否满足saveparam数组里面设置的条件,如果只要符合其中的一个条件,就会执行BGSAVE命令。

  • RDB文件的结构

    • RDB文件结构分为五大部分。分别为REDIS,db_version,database,EOF,check_sum。
      • REDIS,通过这个部分可以快速检查所载入的文件是否是RDB文件。
      • db_version,表示使用的redis的版本
      • databases,里面有零个或者是多个数据库,每个数据库里面存储的是对应的键值对数据。
        • 对于每个database,里面有三个元素,分别为SELECTDB,db_number,key_value_pairs。
          • SELECTDB是一个常量,表示接下来要读入一个数据库号码。
          • db_number表示的是一个数据库号码。
          • key_value_pairs部分保存的是键值对数据。
      • EOF,用来表示读取的RDB的正文内容已经结束了。
      • check_sum,校验和,是根据前面的四个属性得到的一个校验和。服务器在载入RDB文件的时候,会一边计算这个值,最后再和check_sum进行比较,用来判断文件是否出错或者是损坏。
  • 总的来说,RDB文件大致的结构如图
    alt

AOF持久化

  • AOF是通过保存Redis服务器所执行的写命令来记录数据库的状态。被写入的命令都是以纯文本的格式写入的,所以我们可以直接打开查看。大概是下面这种的
    alt

  • 写入和同步

    • 由于AOF会暂时将一部分命令写到缓冲区里面,等到了一定的条件之后才会落盘。所以,这里其实是有丢失数据的风险的。为此,Redis系统提供了fsync和fdatasync两个同步函数,目的是强制让缓冲区的数据写入到硬盘中。
    • 这里,我们首先要理解写入AOF和同步AOF。写入就是在每个Redis事件循环我们都需要将命令写入到AOF缓冲区里面,而同步AOF则是将缓冲区里面的文件落盘,这个由Redis的配置决定的。同时AOF的参数是appendfsync,这个参数有三种选项,分别为always,everysec和no。
      • always,表示服务对于事件循环都需要同步AOF文件。
      • everysec,表示的是每隔一秒就进行同步。
      • no,同步AOF文件由系统控制。
        alt
  • 数据的载入和还原

    • Redis服务器会通过创建一个伪客户端来逐条读取AOF文件的内容,然后执行。这个伪客户端不同于正常的客户端,不需要和服务器之间进行网络通信,但是效果和正常的客户端基本一样。
    • 我们知道,AOF存储的是逻辑日志,随着我们的服务运行时间越长,积累的命令越来越多,我们的文件也会越来越大,这个时候Redis服务器会有一个对AOF重写的优化。
      • 举个例子,比如Redis依次执行了SET name Mike,SET name Peter,SET name Joy,那么我们的AOF就会依次记录这三条命令,但是其实这三条命令的效果类似于SET name Joy。到了这里很多人可能会说那么AOF重写就是读取目前AOF已有的命令,然后进行一个合并。但是其实不是这样的。Redis的AOF重写不需要对现有的AOF文件进行任何读取,分析或者是写入操作。这个功能是通过读取当前服务器的状态来实现的。
    • 为了避免由于重写AOF阻塞服务,一般会采用开一个子线程来后台进行重写。这样不仅可以让服务进行处理请求,同时使用父子进程关系还可以避免使用锁的情况,数据更加安全。
    • 但是这里稍微用心一点就可以发现,我们还是用上面的例子,假如我们此时重写的时候name是Joy,但是之后父进程可能又将这个name修改为了Pony,那么我们这个重写就是与数据不符合的。为了解决这种问题,Redis设置了一个重写缓冲区。在子进程重写AOF期间,会将命令分别写到AOF缓冲区和AOF重写缓冲区里面。最后在子进程重写完之后,会将缓冲区里面的内容写到新的AOF文件里面,这样,可以保证我们的数据的一致性了。

混合持久化机制

  • 对于使用AOF或者是RDB进行持久化,各有优缺点,AOF丢数据少,但是性能较低,RDB丢数据多,但是性能表现更好。所以在Redis4.0之后,为了解决这个问题,就出现了混合持久化机制,具体是通过将RDB格式的数据和AOF格式的数据混合写入新的AOF文件里面,然后通过读取这个AOF文件来重放。
  • 在开启混合持久化的时候,首先会fork一个子进程全量将内存副本的数据以RDB的数据格式写入到AOF文件里面,然后对于这个期间内缓冲区里面的增量的数据,通过AOF的格式来写入。这样的话这个AOF文件的前半部分就是RDB格式的数据,后半部分就是缓冲区里面的增量的AOF格式的数据。

总结

  • 最后,对RDB和AOF做一个简单的对比
RDB AOF
物理日志 逻辑日志
二进制数据 文本数据
宕机丢失数据更多 宕机丢失数据更少
通常文件更小 通常文件更大

相关面试题汇总

  • redis的持久化机制是什么?
  • RDB原理是什么?AOF原理是什么?
  • RDB和AOF的优缺点是什么?
  • AOF重写机制是怎样的?
  • RDB的执行流程是什么?AOF的执行流程是怎么样的?
  • AOF的同步策略有哪些?
  • 介绍一下redis的混合持久化机制?

如果这篇文章对你有帮助的话,求求点赞加收藏,谢谢啦

近期帖子

互联网面试算法题题解大合集(强烈建议收藏)
互联网话术你知多少?(长期更新中...)

#面试##知识点#
全部评论
狠狠的赞了一下😋
点赞 回复 分享
发布于 2022-06-06 23:58
讲的挺详细啊
点赞 回复 分享
发布于 2022-06-07 12:41
完全看不懂,但是给你点个赞叭
点赞 回复 分享
发布于 2022-06-09 08:51
peter我的peter😘
点赞 回复 分享
发布于 2022-06-18 22:44

相关推荐

20 54 评论
分享
牛客网
牛客企业服务