参考书籍《Redis设计与实现》

一丶为什么redis需要持久化

redis 作为一个内存数据库,如果不想办法将存储在内存中的数据,保存到磁盘中,那么一旦服务器进程退出,那么redis数据库中的数据就将丢失。

二丶RDB

redis 提供RDB持久化功能,可以将数据库中的数据保存到磁盘中,避免数据意外丢失。Redis RDB 是将一个时间点的数据库状态保存到RDB文件中,RDB文件时一个经过压缩的二进制文件,通过该文件可以还原申生成RDB时的数据库状态。

1.SAVE与BGSAVE

SAVE和BGSAVE 命令都能生成RDB文件

  • SAVE命令会阻塞redis服务器进程,直到SAVE命令执行完为止,在服务器进程阻塞的期间,服务器无法处理任何命令请求
  • BGSAVE会派生出一个子进程,然后由子进程负责创建RDB文件,服务器进程可以继续处理请求命令

Redis 服务在启动的时候会检测RDB文件的存在,并自动载入RDB文件。由于AOF文件更新的频率比RDB高(频率高意味着数据全),所以如果同时具备AOF 和RDB文件,redis服务器会选择AOF文件进行恢复。

BGREWRITEAOF 可以触发AOF持久化,但是不允许和BGSAVE一起执行(因为一起执行意味着大量的磁盘写入操作)

2.RDB自动间隔保存

redis 允许用户通过配置save选项,让服务器每隔一段时间自动执行一次BGSAVE命令。如

save 900 1
save 300 10
save 60 1000

这个配置意味着,如果900秒内对数据库进行至少一次修改,300秒内对数据库至少由十次修改,60秒内有1000次修改,那么redis服务器将自动进行BGSAVE命令的执行。

为了实现这个功能redis服务器会记录两个内容:dirty(距离上一次成功执行save 或者bgsave 数据库进行了多少次修改)和 lastsave (时间戳,记录上一次执行save 或者 bgsave 的时间)。redis 周期性操作函数serverCron每隔100毫秒执行一次,会根据dirtylastsave是否满足 save 900 1等配置的要求,如果满足那么将执行BGSAVE

三丶AOF

除了RDB之外,redis 还有AOF(append only file)持久化的功能,与RDB持久化通过将数据库数据保存到文件中不同,AOF 持久化时通过保存redis服务器执行的修改操作命令来实现的。如

set msg "hello"

对于这条命令,RDB记录的是msg 键和对应的值,但是AOF记录的是set msg "hello"这条命令。AOF持久化可以使用BGREWRITEAOF触发

AOF可以分为如下流程

image-20230102182436931

1.命令追加

服务器在执行完一个写明了后,会以协议格式将被执行的命令追加到redis服务器中的aof_buf末尾

2.AOF 文件写入和同步

redis每次结束一个事件循环之前都会调用flushAppendOnlyFile来判断是否需要将aof_buf里的内容写入到AOF文件中。redis服务器配置的appendfsync 设置可以控制aof 文件写入的时机:

  • always

    将aof缓冲区的所有内容写入并且同步到aof文件

    选择此配置,意味着每次都需要将命令写回磁盘,安全性最高,但是会导致效率很低

  • everysec

    每秒写入aof缓冲区中的内容,并同步aof文件(同步操作由另外一个线程专门进行)

    选择此配置,意味着每秒写回磁盘,最多丢失一秒的数据

  • no

    将aof缓冲区中的内容写入到AOF文件但是不同步,何时同步由操作系统决定

    此配置不会将命令马上写回磁盘,效率高,但是不安全

为了提高文件的写入效率,在现代操作系统中,用户调用write函数,将一些数据写入到文件的时候,操作系统通常会将期望写入的数据保存到一个内存缓冲区中,等缓冲区满或者超过一段事件后,才真正的将缓冲数据写入到磁盘
这样的操作提高的效率,但是带来了数据丢失的风险,所以操作系统提供了fsync 和fdatasync两个同步函数,让用户调用强制让缓冲区写入磁盘,从而确保数据的安全性

3.AOF重写

因为aof文件记录的是数据库执行的修改操作命令,这意味着随着时间的流逝,aof文件中的内容将越来越多。为了解决这个问题redis使用AOF重写——redis服务器可以创建一个新的aof文件来替代现有的aof文件,二者保存的数据库数据相同,但是新的文件不会保存冗余命令(set msg "a" 然后执行set msg "b" 其实aof文件只需要保存set msg "b" )

3.1 AOF 重写原理

AOF重写并不是分析已有文件,而是读取数据库中的数据,将数据转化为命令。首先读取数据库中的键和值,然后使用一条命令来记录键值对,这就是aof重写的实现原理(对于哈希,集合,有序集合,列表键值对,redis一条命令只会记录64个元素,超过64个元素,将使用多条命令记录)

3.2 AOF 后台重写

AOF重写程序将使用子进程的方式执行命令,从而让服务器进程可以继续处理请求。

为了解决重写过程中,键值对被修改的问题,redis使用aof重写缓冲区,在重写过程中,用户修改数据库的命令会被保存到AOF缓冲区和AOF重写缓冲区。子进程完成AOF重写后,会将AOF重写缓冲区中的命令同步到新AOF文件中,这时候新文件保存的内容就和数据库一致了。然后子进程将修改新AOF文件名称,原子的覆盖旧AOF文件。