Redis 的持久化有三种方式:
- RDB 快照 :将数据库的某个状态的内存数据,以二进制的方式写入磁盘中。
- AOF 文件追加(Append Only File):记录所有的操作命令,并以文本的形式追加到文件中
- 混合持久化方式:这是 Redis4.0 之后的功能,结合了 RDB 和 AOF 的优点。用AOF来保证数据不丢失,作为数据恢复的第一选择;用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复
RDB
RDB 是 Redis DataBase 的简称,它是将某个时刻的内存快照(Snapshot),以二进制的方式写入到磁盘中。那么如何将数据写入到磁盘中呢,如何触发 RDB 的持久化呢,这里是分为手动保存和自动保存两种模式。
手动保存
执行RDB持久化的操作命令有两个,save和bgsave。
save
save命令会直接阻塞服务器进程,直到 RDB 文件创建完毕,在此期间,服务器不能处理任何命令请求。
bgsave
bgsave命令会派生出一个子进程,然后子进程去创建 RDB 文件,服务器进程继续处理命令请求。
自动保存
在redis 的配置中 有个 save 选项,可以实现自动间隔保存,此外,在执行 flushall、主从同步的时候也会触发自动保存。
save
Redis 的配置中有个 save 命令,注意的是,可能有些读者会认为这 save 与前面的 save 是一个命令,但它实际上执行的是 bgsave。是要创建子进程去保存 RDB 文件的。 触发的条件如下,注意的是 Redis 的快照是全量快照,每一次触发的时候要把当前的内存数据都记录到磁盘中,如果在数据量很大的时候频繁执行是会对 Redis 的性能产生影响的。
127.0.0.1:6379> config get save
1) "save"
2) "900 1 300 10 60 10000"
- save 900 1:表示900 秒内如果至少有 1 个 key 的值变化,则保存
- save 300 10:表示300 秒内如果至少有 10 个 key 的值变化,则保存
- save 60 10000:表示60 秒内如果至少有 10000 个 key 的值变化,则保存
flushall
这个命令用来清空数据库,如果执行了,会生成 dump.rdb 文件
退出触发
退出 redis 的时候也会触发持久化,生成 dump.rdb 文件
主从同步触发
在 Redis 主从复制中,当从节点执行全量复制操作时,主节点会执行 bgsave 命令,并将 RDB 文件发送给从节点,该过程会自动触发 Redis 持久化。
优点
- RDB非常适合做冷备,占用内存小,对容灾恢复比较有用。
- RDB对redis对外提供的读写服务,影响非常小,可以让redis保持高性能,因为redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可
- 相对于AOF持久化机制来说,直接基于RDB数据文件来重启和恢复redis进程,更加快速
缺点
- RDB 容易丢失数据,一旦宕机,最近几分钟的数据都没了
- RDB 在fork 子进程生成大文件数据的时候,可能会导致redis 性能下降,造成服务器短暂暂停提供服务,一般为几毫秒。
AOF 持久化功能的实现可以分为命令追加(append)、文件写入(write)、文件同步(sync)三个步骤。
AOF 持久化的实现
命令追加
当 AOF 持久化功能处于打开状态时,服务器在执行完一个写命令之后,会以协议格式将被执行的写命令追加到服务器状态的 aof_buf 缓冲区的末尾:
strct redisServer {
// ...
// AOF 缓冲区
    sds aof_buf;
// ...
};
举个例子,如果客户端向服务器发送以下命令:
redis> SET KEY VALUE
OK
那么服务器在执行这个 SET 命令之后,会将以下协议内容追加到 aof_buf 缓冲区的末尾:
*3\r\n$3\r\nSET\r\n$3\r\nKEY\r\n$5\r\nVALUE\r\n
文件的写入与同步
Redis 的服务器进程就是一个事件循环(loop),这个循环中的文件事件负责接收客户端的命令请求,以及向客户端发送命令回复,而时间事件则负责执行像 serverCron 函数这样需要定时运行的函数。
因为服务器在处理文件事件时可能会执行写命令,使得一些内容被追加到 aof_buf 缓冲区里面,所以在服务器每次结束一个事件循环之前,它都会调用 flushAppendOnlyFile 函数,考虑是否需要将 aof_buf 缓冲区中的内容写入和保存到 AOF 文件里面。
flushAppendOnlyFile 函数的行为由服务器配置的 appendfsync 选项的值来决定,各个不同值产生的行为如表 TABLE_APPENDFSYNC 所示。
127.0.0.1:6379> config get appendfsync
1) "appendfsync"
2) "everysec"
| appendfsync选项的值 | flushAppendOnlyFile函数的行为 | 
|---|---|
| always | 将 aof_buf缓冲区中的所有内容写入并同步到 AOF 文件。 | 
| everysec(默认) | 将 aof_buf缓冲区中的所有内容写入到 AOF 文件,如果上次同步 AOF 文件的时间距离现在超过一秒钟,那么再次对 AOF 文件进行同步,并且这个同步操作是由一个线程专门负责执行的。 | 
| no | 将 aof_buf缓冲区中的所有内容写入到 AOF 文件,但并不对 AOF 文件进行同步,何时同步由操作系统来决定。 | 
为了提高文件的写入效率,在现代操作系统中,当用户调用 write 函数,将一些数据写入到文件的时候,操作系统通常会将写入数据暂时保存在一个内存缓冲区里面,等到缓冲区的空间被填满、或者超过了指定的时限之后,才真正地将缓冲区中的数据写入到磁盘里面。
这种做法虽然提高了效率,但也为写入数据带来了安全问题,因为如果计算机发生停机,那么保存在内存缓冲区里面的写入数据将会丢失。
为此,系统提供了 fsync 和 fdatasync 两个同步函数,它们可以强制让操作系统立即将缓冲区中的数据写入到硬盘里面,从而确保写入数据的安全性。