本片主要复习下redis的两种持久化方法的原理、载入过程以及使用的利弊,还有面试经常会被问到的一些相关问题。
redis有一个文件是非常重要的,就是redis.conf文件;可以再里面修改配置,启动redis的时候是后台启动还是正常启动;又或者是修改默认启动占用端口都是在该文件中配置,所以是否启动RDB或者AOF也是在该文件中配置;这个文件在这里也就说这么多,有人想要更了解的话可以自己再深入研究下这个文件;
平时经常听到的一个词“快照”,在redis中说的就是RDB持久化;那快照的意思就是说在某一瞬间以照片的形式把数据保存下来。这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。
虽说在redis.conf开启了持久化功能,那肯定也需要在某一时刻开启该功能;所以需要命令去触发该机制,触发该机制的方法有三种:save、bgsave、自动化;
那三种方法一一来分析下有什么不同:
1.save:
(借用网上的一张图片)
也就是说在执行了save命令之后,服务器是不能再处理客户端发来的请求,直到save执行完毕(那在正常的情况下,显然这种方法是不可取的);在执行完save命令之后,新的RDB文件会代替旧的RDB文件。
2.bgsave:
和SAVE命令直接阻塞服务器进程的做法不同,BGSAVE命令会派生出一个子进程,然后由子进程负责创建RDB文件,服务器进程(父进程)继续处理命令请求;
(借用网上的另一张图片)
当然在这个命令执行的过程中也会产生阻塞,那就是在fork()子进程的时候会阻塞服务器进程;
直接去网上拿一张save和bgsave的比较图:
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函数追加到文件中。
上图(非自制)
一个命令过来就保存到AOF中,一个命令过来就保存(当然这个保存频率是配置的,这里说的只是一个命令保存一次只是举例而已)
在redis.conf中设置成yes就行了
appendonly yes
写入的频率有三种策略:(这里的写入其实是先写入缓冲区,然后再写入AOF文件)
always:每次有新命令追加到 AOF 文件时就执行一次 fsync :非常慢,也非常安全。
everysec:每秒 fsync 一次:足够快(和使用 RDB 持久化差不多),并且在故障时只会丢失 1 秒钟的数据。(默认方式,速度和安全都兼顾)
no:这种策略的话一般就是系统等缓冲区存满了之后就会把数据写入AOF文件中(非常不安全)
由于每条命令都会被记录,所以有很多重复的命令也都会被记录进去,例如第一次set 100个数字进去。第二次还是set 100个数字,第N次set,这样AOF文件就会被变臃肿,此时就需要进行AOF重写来。
bgrewriteaof:与RDB的bgsave原理相似,也是通过fork()子进程来就行重写。
即使 bgrewriteaof 执行失败,也不会有任何数据丢失,因为旧的AOF文件在 bgrewriteaof 成功之前不会被修改。(整个流程入下图)
AOF重写过程:
(1)首先redis服务fork出一个子进程,该子进程的主要目地就是不依赖已存在的AOF文件,仅仅通过redis中已有的数据生成新的AOF文件;
(2)主进程将实时的redis中的数据变动写入AOF缓冲区(这个数据是要写入老AOF文件中的)和重写缓冲区;
(3)子进程通知主进程完成对旧数据的AOF重写;
(4)主进程现在将重写缓冲文件添加到子进程完成重写之后的AOF文件之后,形成新的AOF文件,替代老的AOF文件
AOF的重写可自动触发,也可手动触发,手动触发就是用bgrewriteaof命令进行操作,那自动触发是根据配置来进行的;
举例说明:
当AOF文件的体积大于64Mb,并且AOF文件的体积比上一次重写之久的体积大了至少一倍(100%)时,Redis将执行 bgrewriteaof 命令进行重写。
auto-aof-rewrite-min-size 64mb
auto-aof-rewrite-percentage 100
下图是AOF在redis.conf中的一些相关配置
AOF的优点(优缺点的总结就直接借用了,毕竟自己总结的不是很好)
- AOF 会让你的Redis更加耐久: 你可以使用不同的fsync策略:无fsync,每秒fsync,每次写的时候fsync。使用默认的每秒fsync策略,Redis的性能依然很好(fsync是由后台线程进行处理的,主线程会尽力处理客户端请求),一旦出现故障,你最多丢失1秒的数据。
- AOF文件是一个只进行追加的日志文件,所以不需要写入seek,即使由于某些原因(磁盘空间已满,写的过程中宕机等等)未执行完整的写入命令,你也也可使用redis-check-aof工具修复这些问题。
- Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。
- AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF 文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松。 导出(export) AOF 文件也非常简单: 举个例子, 如果你不小心执行了 FLUSHALL 命令, 但只要 AOF 文件未被重写, 那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL 执行之前的状态。
AOF的缺点
- 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。
- 根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)。
两种持久化的方式都介绍完了,实际使用中到底用哪一种呢,其实大部分时候都是两种结合着使用是最好的,
三:启动redis的时候数据的加载:
启动服务器加载数据的时候,服务器是一直处于阻塞状态的,直到载入工作完成后才会改变状态;
如果同时存在RDB持久化和AOF持久化,redis启动时怎么加载数据的呢?
开启了AOF持久化功能,那么服务器会优先使用AOF文件来还原数据库状 态,那么就不会使用RDB文件了只有在AOF持久化功能处于关闭状态时,服务器才会使用RDB文件来还原数据库状态
为什么AOF文件大于RDB文件,但还是优先使用AOF文件加载呢?
RDB与AOF同时开启 默认无脑加载AOF的配置文件相同数据集,AOF文件要远大于RDB文件,恢复速度慢于RDB,AOF运行效率慢于RDB,但是同步策略效率好,
加载流程图:
载入RDB文件的实际工作由rdb.c/rdbLoad函数完成,这个函数和rdbSave函数之间的关系可以如下图所示:
以上就是对RDB和AOF持久化的介绍,如有不足或说错的地方,欢迎大家批评改正。