前言:redis还提供了AOF持久化功能。于RDB持久化不同,AOF持久化是通过保存redis服务器所执行的写命令来记录数据库状态的。服务器在启动时,通过载入和执行AOF文件中保存的命令,来还原服务器关闭之前的数据库状态。
1、AOF持久化的实现
AOF持久化的实现可以分为命令追加(append)、文件写入、文件同步(sync)三个步骤。
1.1、命令追加
当AOF功能出于打开的状态,服务器执行完一个写命令之后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区的末尾。
struct redisServer{
sds aof_buf; // AOF缓冲区,SDS底层实现
}
举个例子, 如果客户端向服务器发送以下命令:SET KEY VALUE
那么服务器在执行这个 SET 命令之后, 会将以下协议内容追加到 aof_buf 缓冲区的末尾:*3\r\n$3\r\nSET\r\n$3\r\nKEY\r\n$5\r\nVALUE\r\n
1.2、AOF文件的写入同步
Redis 的服务器进程就是一个事件循环(loop), 这个循环中的文件事件负责接收客户端的命令请求, 以及向客户端发送命令回复, 而时间事件则负责执行像 serverCron 函数这样需要定时运行的函数。
因为服务器在处理文件事件时可能会执行写命令, 使得一些内容被追加到 aof_buf 缓冲区里面, 所以在服务器每次结束一个事件循环之前, 它都会调用 flushAppendOnlyFile 函数, 考虑是否需要将 aof_buf 缓冲区中的内容写入和保存到 AOF 文件里面, 这个过程可以用以下伪代码表示:
flushAppendOnlyFile 函数的行为由服务器配置的 appendfsync 选项的值来决定(默认everysec)。
注意,文件的写入和和同步是有区别的。
1.3、AOF持久化的效率和安全性
always安全性最好,但是效率最低。
everysec效率也足够快,并且就算出现故障停机,数据库也只丢失一秒钟的命令数据。
no模式下的AOF写入速度总是最快的,但是同步AOF文件的市场也是最长的。
2、AOF文件的载入与数据还原
其中,第一步是创建一个伪客户端。因为redis的命令只能在客户端上下文中执行,而载入AOF文件时所使用的命令全部都是来源于AOF文件而不是网络连接,所以服务器创建了一个没有网络连接的伪客户端来执行AOF文件总的写命令。
3、AOF重写
由于AOF持久化是通过保存写命令来记录数据库状态的,所以随着服务器运行时间的流逝,AOF文件的内容会越来越多 。文件体积会越来越大。如果不加以控制,文件的体积越来愈大,对redis服务器甚至整个宿主计算机造成影响。另外,体积过大的AOF文件,数据恢复的时间也越来越多。
因此,redis提供了AOF重写功能。AOF文件重写并不需要对现有AOF文件进行任何读取、分析或者写入操作,这个功能是通过读取服务器当前的数据库状态来实现的。
3.1、AOF后台重写
AOF重写会有大量的写入操作,会长期阻塞。因为redis是单线程来处理请求命令,所以在AOF重写期间,服务器将无法处理客户端发来的命令请求。
所以redis决定将AOF重写放在子进程里面。放在子进程而不是子线程,主要是由于使用子进程,可以在避免使用锁的情况下,保证数据的安全性。
3.2、重写缓冲区
子进程在重写阶段,服务器的主进程还要继续处理命令操作,而新的操作如果对现有数据库进行修改,会导致重写后的AOF文件和数据库状态不一致。
因此,redis服务器创建了一个AOF重写缓冲区。这个缓冲区在服务器创建子进程之后开始使用,当redis服务器操作完一个写命令后,用时将这个写命令发送给AOF缓冲区和AOF重写缓冲区。
3.3、何时触发AOF重写
重写配置在配置文件中对应的是
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
前者是指超过上一次aof重写aof文件大小的百分之多少,会再次优化,如果没有重写过,则以启动时为主。
后者是限制了允许重写的最小aof文件大小。最少AOF文件多大才开始重写。