深入了解Redis之Redis的持久化方式

我们知道Redis是一个内存数据库,它所有的数据库状态都存储在内存中,所以如果想要在服务器故障、重启之后数据还在,就需要一个将这些数据持久化的一个功能。

redis持久化原理

Redis提供了两种持久化的方式,

  • RDB 持久化方式

    将数据库中的键值对及状态保存在持久化文件中

  • AOF 持久化方式

    而AOF保存的是服务器所执行过的所有写命令

服务器载入文件时的判断流程

值得提一下的是,因为AOF文件的更新频率通常比RDB文件的更新频率更高,所以如果服务器有开启AOF持久化功能时,服务器就会优先使用AOF文件来还原数据库,其次才是RDB文件。

RDB 持久化方式

RDB文件结构简析

RDB文件结构

redis服务器保存和载入RDB文件的方法

redis中创建RDB文件的两个命令

  • SAVE
    SAVE命令会由Redis服务器主进程来执行RDB文件的创建,所以在执行SAVE时,Redis服务器会有阻塞,知道RDB文件创建完毕为止,且在阻塞期间服务器不能处理任何命令请求。

  • BGSAVE
    BGSAVE命令则会派生出一个子进程,然后由子进程负责创建RDB文件,而Redis服务器主进程(父进程)可以继续处理各种命令请求。

创建RDB文件的实际工作由rdb.c/rdbSave函数来完成,SAVE和BGSAVE命令都会以不同的形式调用这个函数。

RDB文件载入时的服务器状态

RDB文件的载入只有在服务器启动时才会被执行,所以Redis中没有专门载入RDB文件的命令,只要Redis启动时没有开启AOF功能,且检测到RDB文件的存在,就会自动载入RDB文件。且服务器在载入RDB文件期间,会一直处于阻塞状态,直到载入工作完成。

redis服务器自动保存功能的实现原理

通过上面我们知道,Redis服务器有两个命令,SAVE和BGSAVE,来执行保存数据库状态的操作。
SAVE是阻塞的,BGSAVE是非阻塞的。Redis中借助BGSAVE命令,每隔一段时间自动执行一次BGSAVE命令来实现数据库状态的自动保存功能。

具体实现是通过设置服务器配置的save选项,按照一定的周期去执行BGSAVE命令。如

save 900 1
save 300 10
save 60 10000

那么只要满足上面这三个条件的任何一条,BGSAVE就会被执行。

  • 服务器在900s之内,对数据库进行了至少1次修改
  • 服务器在300s之内,对数据库进行了至少10次修改
  • 数据库在60s之内,对数据库进行了10000次修改

AOF 持久化方式

AOF持久化方式

AOF持久化的实现

当AOF持久化功能处于打开的状态时,服务器在执行完一个写命令,先将被执行的写命令追加到服务器状态的 aof_buf 的缓冲区。Redis服务器会在每次事件循环结束之前,都会调用“flushAppendOnlyFile”函数来判断是否需要将 aof_buf 缓冲区中内容保存到AOF文件里面。

flushAppendOnlyFile 函数判断是否保存的依据和配置(appendfsync)

  • always,将aof_buf 将缓冲区中所有内容写入并同步到AOF文件
  • everysec,将缓冲区中所有内容写入AOF文件,但至少间隔一秒同步一次(默认值)
  • no,将缓冲区中所有内容写入AOF文件,但不对AOF文件进行同步,何时同步则由系统决定

AOF文件的载入与数据还原

AOF文件载入过程

AOF重写的原理和实现

随着服务器运行时间的增加,AOF文件中的内容会越来越多,相应的文件体积就会越来越大,但其实文件中很大一部分信息是冗余信息。

例如,我们对一个键进行了n次的写操作,AOF文件中相对应就会产生n次的写操作命令。但其实AOF文件中的对于该键的前n-1次的写操作命令都可认为是冗余操作命令,只需保留最后一条的写操作命令即可。

所以,Redis提供了AOF文件重写(rewrite)功能,来清除这些冗余命令,以控制AOF文件的大小。具体实现思路为,Redis服务器先创建一个新的AOF文件来替代现有的AOF文件,新旧两个AOF文件所保存的数据库状态是相同的,但新的AOF文件不会包含任何浪费空间的冗余命令。

Redis服务器AOF重写的实现

  • 虽然该功能名称叫 AOF文件重写 ,但是具体的实现却并没有对现有AOF文件进行任何读取、分析、或者写入操作,而是通过读取当前服务器的数据库状态来实现的。

  • 通过读取当前数据库中键值的状态,尽量生成最少的能与之对应redis命令,然后将该redis命令写入新的AOF文件中,直至将当前数据库状态全部生成完毕。

  • 另外,在执行AOF重写的期间,Redis会维护一个AOF重写缓冲区,该缓冲区会在子进程创建AOF文件期间,记录服务器执行的所有写命令。当子进程完成创建新AOF文件之后,服务器会将重写缓冲区中的所有内容追加到新AOF文件的末尾,使得新旧两个AOF文件所保存的数据库状态完全一致。

  • 最后,服务器用新的AOF替换旧的AOF文件,以此来完成AOF文件的重写操作。

AOF后台重写

由于生成新的AOF文件时会进行大量的写入操作,所以在进行AOF重写的时候,会造成长时间的阻塞,所以redis将AOF重写程序放在子进程里执行,这样就可避免主进程长时间的阻塞。