本片主要复习下redis的两种持久化方法的原理载入过程以及使用的利弊,还有面试经常会被问到的一些相关问题。

redis有一个文件是非常重要的,就是redis.conf文件;可以再里面修改配置,启动redis的时候是后台启动还是正常启动;又或者是修改默认启动占用端口都是在该文件中配置,所以是否启动RDB或者AOF也是在该文件中配置;这个文件在这里也就说这么多,有人想要更了解的话可以自己再深入研究下这个文件;

平时经常听到的一个词“快照”,在redis中说的就是RDB持久化;那快照的意思就是说在某一瞬间以照片的形式把数据保存下来。这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。

虽说在redis.conf开启了持久化功能,那肯定也需要在某一时刻开启该功能;所以需要命令去触发该机制,触发该机制的方法有三种:save、bgsave、自动化;

那三种方法一一来分析下有什么不同:

1.save:

(借用网上的一张图片)


redis存图片视频 redis存储图片_redis 图片2进制保存


也就是说在执行了save命令之后,服务器是不能再处理客户端发来的请求,直到save执行完毕(那在正常的情况下,显然这种方法是不可取的);在执行完save命令之后,新的RDB文件会代替旧的RDB文件。

2.bgsave:

和SAVE命令直接阻塞服务器进程的做法不同,BGSAVE命令会派生出一个子进程,然后由子进程负责创建RDB文件,服务器进程(父进程)继续处理命令请求;

(借用网上的另一张图片)


redis存图片视频 redis存储图片_持久化_02


当然在这个命令执行的过程中也会产生阻塞,那就是在fork()子进程的时候会阻塞服务器进程;

直接去网上拿一张save和bgsave的比较图:


redis存图片视频 redis存储图片_redis_03


3.自动触发:

自动触发的话需要用到redis.conf的配置,在配置表中写入“save m n”(m秒内数据集存在n次修改时,自动触发bgsave。例如:900 秒内如果至少有 1 个 key 的值变化,则保存save 900 1)

此外,还需要一些配置的设置:stop-writes-on-bgsave-error

rdbcompression

rdbchecksum

dbfilename

还要一个问题会被面试官问到:就是在执行bgsave期间,在服务器进程中再次执行save、bgsave和BGREWRITEAOF(AOF下面会讲到)时和平时有什么不同的表现:

1.在BGSAVE命令执行期间,客户端发送的SAVE命令会被服务器拒绝,服务器禁止SAVE命令和BGSAVE命令同时执行是为了避免父进程(服务器进程)和子进程同时执行两个rdbSave调用,防止产生竞争条件;

2.在BGSAVE命令执行期间,客户端发送的BGSAVE命令会被服务器拒绝,因为同时执行两个BGSAVE命令也会产生竞争条件;

3.BGREWRITEAOF和BGSAVE两个命令不能同时执行:

如果BGSAVE命令正在执行,那么客户端发送的BGREWRITEAOF命令会被延迟到 BGSAVE命令执行完毕之后执行如果BGREWRITEAOF命令正在执行,那么客户端发送的BGSAVE命令会被服务器拒绝。

注:BGREWRITEAOF和BGSAVE两个命令的实际工作都由子进程执行,所以这两个命令在操作方面并没有什么冲突的地方,不能同时执行它们只是一个性能方面的考虑——并发出两个子进程,并且这两个子进程都同时执行大量的磁盘写入操作,如果应该这么操作也不是不可以,只是这不是最优操作。

上面说到了 rdbsave这个,其实RDB文件是由rdb.c/rdbSave函数来生成的,在调用save和bgsave时都是调用的rdbSave函数。

RDB 的优势和劣势

优势

(1)RDB文件是以二进制文件进行保存的,而且是全量备份,更适合用于备份和灾难恢复。

(2)生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。

(3)RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

劣势

RDB快照是一次全量备份,存储的是内存数据的二进制序列化形式,存储上非常紧凑。当进行快照持久化时,会开启一个子进程专门负责快照持久化,子进程会拥有父进程的内存数据,父进程修改内存子进程不会反应出来,所以在快照持久化期间修改的数据不会被保存,可能丢失数据。(子进程在做持久化期间,父进程修改的数据会存在一个缓存区,然后子进程会从这个缓存区取出数据同步到RDB文件中,该过程后续再补充下---------

二.再说一下AOF持久化机制:

有全量备份,当然就有增量备份了,AOF就属于增量备份;redis会将每一个收到的写命令都通过write函数追加到文件中。

上图(非自制)


redis存图片视频 redis存储图片_redis 图片2进制保存_04


一个命令过来就保存到AOF中,一个命令过来就保存(当然这个保存频率是配置的,这里说的只是一个命令保存一次只是举例而已)

在redis.conf中设置成yes就行了

appendonly yes

写入的频率有三种策略:(这里的写入其实是先写入缓冲区,然后再写入AOF文件)

always:每次有新命令追加到 AOF 文件时就执行一次 fsync :非常慢,也非常安全。


redis存图片视频 redis存储图片_redis 图片2进制保存_05


everysec:每秒 fsync 一次:足够快(和使用 RDB 持久化差不多),并且在故障时只会丢失 1 秒钟的数据。(默认方式,速度和安全都兼顾)


redis存图片视频 redis存储图片_持久化_06


no:这种策略的话一般就是系统等缓冲区存满了之后就会把数据写入AOF文件中(非常不安全)


redis存图片视频 redis存储图片_redis_07


由于每条命令都会被记录,所以有很多重复的命令也都会被记录进去,例如第一次set 100个数字进去。第二次还是set 100个数字,第N次set,这样AOF文件就会被变臃肿,此时就需要进行AOF重写来。

bgrewriteaof:与RDB的bgsave原理相似也是通过fork()子进程来就行重写。


redis存图片视频 redis存储图片_redis 图片2进制保存_08


即使 bgrewriteaof 执行失败,也不会有任何数据丢失,因为旧的AOF文件在 bgrewriteaof 成功之前不会被修改。(整个流程入下图)

AOF重写过程:

(1)首先redis服务fork出一个子进程,该子进程的主要目地就是不依赖已存在的AOF文件,仅仅通过redis中已有的数据生成新的AOF文件;

(2)主进程将实时的redis中的数据变动写入AOF缓冲区(这个数据是要写入老AOF文件中的)和重写缓冲区;

(3)子进程通知主进程完成对旧数据的AOF重写;

(4)主进程现在将重写缓冲文件添加到子进程完成重写之后的AOF文件之后,形成新的AOF文件,替代老的AOF文件


redis存图片视频 redis存储图片_持久化_09


AOF的重写可自动触发,也可手动触发,手动触发就是用bgrewriteaof命令进行操作,那自动触发是根据配置来进行的;

举例说明:

当AOF文件的体积大于64Mb,并且AOF文件的体积比上一次重写之久的体积大了至少一倍(100%)时,Redis将执行 bgrewriteaof 命令进行重写。

auto-aof-rewrite-min-size 64mb
auto-aof-rewrite-percentage 100

下图是AOF在redis.conf中的一些相关配置


redis存图片视频 redis存储图片_子进程_10


AOF的优点(优缺点的总结就直接借用了,毕竟自己总结的不是很好)

  1. AOF 会让你的Redis更加耐久: 你可以使用不同的fsync策略:无fsync,每秒fsync,每次写的时候fsync。使用默认的每秒fsync策略,Redis的性能依然很好(fsync是由后台线程进行处理的,主线程会尽力处理客户端请求),一旦出现故障,你最多丢失1秒的数据。
  2. AOF文件是一个只进行追加的日志文件,所以不需要写入seek,即使由于某些原因(磁盘空间已满,写的过程中宕机等等)未执行完整的写入命令,你也也可使用redis-check-aof工具修复这些问题。
  3. Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。
  4. AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF 文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松。 导出(export) AOF 文件也非常简单: 举个例子, 如果你不小心执行了 FLUSHALL 命令, 但只要 AOF 文件未被重写, 那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL 执行之前的状态。

AOF的缺点

  1. 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。
  2. 根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)。

两种持久化的方式都介绍完了,实际使用中到底用哪一种呢,其实大部分时候都是两种结合着使用是最好的,


redis存图片视频 redis存储图片_redis_11


三:启动redis的时候数据的加载:

启动服务器加载数据的时候,服务器是一直处于阻塞状态的,直到载入工作完成后才会改变状态;

如果同时存在RDB持久化和AOF持久化,redis启动时怎么加载数据的呢?

开启了AOF持久化功能,那么服务器会优先使用AOF文件来还原数据库状 态,那么就不会使用RDB文件了只有在AOF持久化功能处于关闭状态时,服务器才会使用RDB文件来还原数据库状态

为什么AOF文件大于RDB文件,但还是优先使用AOF文件加载呢?

RDB与AOF同时开启 默认无脑加载AOF的配置文件相同数据集,AOF文件要远大于RDB文件,恢复速度慢于RDB,AOF运行效率慢于RDB,但是同步策略效率好,

加载流程图:


redis存图片视频 redis存储图片_redis存图片视频_12


载入RDB文件的实际工作由rdb.c/rdbLoad函数完成,这个函数和rdbSave函数之间的关系可以如下图所示:


redis存图片视频 redis存储图片_redis 图片2进制保存_13


以上就是对RDB和AOF持久化的介绍,如有不足或说错的地方,欢迎大家批评改正。