第11章,AOF持久化

除了RDB持久化功能之外,Redis还提供了AOF(Append Only File)持久化功能(记录保存数据库状态)。

与RD持久化通过保存数据库中的键值对来记录数据库状态不同,AOF是通过保存Redis服务器所执行的写命令来记录数据库状态的。

如图所示:

举例:在redis客户端执行一下三条命令

RDB持久化保存数据库状态的方法是将msg、fruits、numbers三个键值对保存到RDB文件当中,而AOF持久化保存数据库状态的方法则是将服务器执行的SET 、SADD 、RPUSH三个命令保存到AOF文件中去。

服务器启动时,可以通过载入和执行AOF文件中保存的命令来还原服务器关闭前的数据库状态,以下是服务器载入AOF文件并还原数据库状态时打印的日志:

[8321] 05 Sep 11:58:50.448 # Server started,Redisversion 2.9.11
[8321] 05 Sep 11:58:50.448 * DB loaded from append only file: 0.000 seconds
[8321] 05 Sep 11:58:50.448 * The server is now ready to accept connections on port 6379

11.1 持久化功能的实现,AOF文件写入、保存、载入操作的实现原理

  AOF持久化功能的实现可以分为命令追加(append)、文件写入、文件同步(sync)三个步骤;

11.1.1 命令追加

  当AOF持久化功能处于打开状态时,服务器执行完一个写命令之后,会以协议的格式将被执行的写命令追加到服务器状态的 aof_buf 缓冲区的末尾。

1 struct redisServer {
2         //...
3         //AOF缓冲区
4         sds aof_buf;    
5         //
6 }

11.1.2 AOF文件的写入与同步

  Redis的服务器进程就是一个时间循环(loop),这个循环中的文件事件负责接收客户端的命令请求,以及想客户端发送命令回复;而时间事件则负责执行像serverCron函数这样需要定时执行的函数;

  因为服务器在处理文件事件时可能会执行写命令,使得一些内容被追加到aof_buf 缓冲区,所以服务器在每次结束一个事件循环之前,都会调用 flushAppendOnlyFile 函数,考虑是否将 aof_buf 缓冲区的内容写入和保存到 AOF 文件里面;

  flushAppendOnlyFile 函数的行为是有服务器配置的 appendfsync 选项的值来决定,各个不同的值产生的行为如下表所示:

appendfsync 选项的值 flushAppendOnlyFile 函数的行为 效率与安全性
always 每次事件循环都要将 aof_buf 缓冲区的所有内容写入并同步到 AOF 文件; 写入最慢;最安全(最多丢失一个事件循环中所所产生的命令数据)
everysec(默认值) 每次事件循环都要将 aof_buf 缓冲区的所有内容写入AOF文件;每隔一秒钟在子线程中都要对 AOF 文件进行同步,并且这个同步操作是由2一个线程专门负责的; 写入足够快,并且计算出现故障停机,数据库最多丢失一秒钟的命令数据;
no 每次事件循环都要将 aof_buf 缓冲区的所有内容写入AOF文件;何时对 AOF 进行文件进行同步由操作系统决定; 写入最快;同步时长最长,并且计算出现故障停机,服务器丢失上次同步 AOF 文件之后的所有写命令数据l;
操作系统——文件的吸入与同步

 为了提高文件的写入效率,现在操作系统中,当用户调用write函数,将一些数据写入到文件时,OS通常会将写入的数据暂时保存在一个内存缓存区里面,等缓冲区的空间被填满,或者超过指定的时限之后,才真正地将缓冲区数据写入到磁盘当中;

  这种做法虽然提高了效率,也为数据写入带来了安全问题,一位如果计算机发送停机故障,那么保存在内存缓冲区的写入数据将会丢失;

  为此,OS提供了 fsync 和 fdatasync 两个同步函数,它们可以强制让操作系统立即将缓冲区的数据写入到硬盘当中,从而确保数据写入的安全性;

11.2 AOF 文件的载入与还原

  因为 AOF 文件里面包含了重建数据库状态所需要的所有写命令,所以服务器只要读入并重新执行一遍 AOF 文件里面保存的写命令,就可以还原服务器关闭之前的数据库状态;

  Redis 读取 AOF 文件并还原数据库状态的详细步骤:

  

11.3 AOF 重写

  随着时间的流逝,AOF 文件中的内容越来越多,文件体积越来越大,如果不加以控制,体积过大的 AOF 文件很可能对 Redis 服务区、甚至整个宿主计算机造成影响,并且 AOF 文件的体积越大,使用 AOF 文件对数据进行还原所需要的时间越多。

  为了解决 AOF 体积膨胀问题,Redis提供了 AOF 文件重写(rewrite)功能:Redis服务器通过创建一个新的 AOF 文件替代现有的 AOF 文件,新旧两个文件保存的数据库状态相同,但是新的 AOF 文件不会保存任何浪费空间的冗余命令;

  实现原理:该功能并不需要对现有的 AOF 文件进行任何读取、分许或者写入操作;而是通过读取服务器当前数据库状态来实现的。

  AOF 后台重写:AOF 重写程序 aof_rewrite 函数可以很好的完成创建一个新 AOF 文件的任务,但是因为该函数会进行大量的写入操作,所以调用此函数的线程将会长时间被阻塞;

    因为Redis服务器使用单线程处理命令请求,所以如果由服务器直接调用 aof_rewrite 函数。那么在重写期间,服务器将无法处理客户端发送来的命令请求;

    所以Redis决定将AOF重写程序放入到子进程中去执行;

  使用子进程所带来的问题:

    新的客户端命令请求会修改当前数据库的状态,引发服务器当前数据库状态与重写后 AOF 文件保存的数据库状态不一致!

    为了解决这个问题,Redis服务器设置类以一个 AOF 重写缓冲区,该缓冲区是在服务器创建子进程之后开始使用,当服务器执行完一个写命令之后,它会同时将这个写命令发送给 AOF 缓冲区和 AOF 重写缓冲区,如图所示:

  

  在子进程执行 AOF 重写期间,服务器进程需要执行一下三个工作:

  (1)执行客户端发送得命令;

  (2)将执行后得写命令追缴到 AOF 缓冲区;

  (3)将执行后得写命追加到 AOF 重写缓冲区;

  当子进程完成 AOF 重写工作之后,它会给父进程发送一个信号,父进程在接受到信号之后,会调用一个信号处理函数,并执行以下工作:

  (1)将 AOF 重写缓冲区得所有内容写入到新 AOF 文件中,这时,新AOF文件所保存的数据库状态和服务器当前数据库状态保持一致;

  (2)对新 AOF 文件改名:原子地覆盖现有 AOF 文件,完成新旧两个 AOF 文件的替换;

  信号处理函数执行完成之后,父进程就可以正常处理接受命令请求了;

  在整个 AOF 后台重写过程中,只有信号处理函数会对服务器进程(父进程)造成阻塞,在其它时候,AOF 后台重写都不会阻塞父进程,这将 AOF 重写对服务器的性能造成的影响降到了最低;

猜你喜欢

转载自www.cnblogs.com/luoshengjie/p/11114074.html