为了解决AO文件体积越来越大的问题,Redis提供了AOF文件重写功能,即Redis服务器会创建一个新的AOF文件来替代现有的AOF文件,新旧两个AOF文件所保存的数据库数据相同,但新AOF文件不会包含任何浪费空间的冗余命令,所以新AOF文件的体积通常会比旧AOF文件的体积要小很多。
3.3.1 AOF重写的实现原理AOF文件重写并不需要对现有的AOF文件进行任何读取、分析或者写入操作,而是通过读取服务器当前的数据库数据来实现的。
仍然以上面的list键为例,旧的AOF文件保存了6条命令来记录list键的状态,但list键的结果是“C” "D" "E" "F" "G"这样的数据,所以AOF文件重写时,可以用一条RPUSH list “C” "D" "E" "F" "G"命令来代替之前的六条命令,这样就可以将保存list键所需的命令从六条减少为一条了。
按照上面的原理,如果Redis服务器存储的键值对足够多,AOF文件重写生成的新AOF文件就会减少很多很多的冗余命令,进而大大减小了AOF文件的体积。
综上所述,AOF文件重写功能的实现原理为:
首先从数据库中读取键现在的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令。
3.3.2 AOF后台重写因为AOF文件重写会进行大量的文件写入操作,所以执行这个操作的线程将被长时间阻塞。
因为Redis服务器使用单个线程来处理命令请求,所以如果由服务器进程直接执行这个操作,那么在重写AOF文件期间,服务器将无法处理客户端发送过来的命令请求。
为了避免上述问题,Redis将AOF文件重写功能放到子进程里执行,这样做有以下2个好处:
子进程进行AOF文件重写期间,服务器进程(父进程)可以继续处理命令请求。
子进程带有服务器进程的数据副本,使用子进程而不是线程,可以在避免使用锁的情况下,保证数据的安全性。
AOF后台重写的步骤如下所示:
服务器进程创建子进程,子进程开始AOF文件重写
从创建子进程开始,服务器进程执行的所有写命令不仅要写入AOF缓冲区,还要写入AOF重写缓冲区
写入AOF缓冲区的目的是为了同步到原有的AOF文件。
写入AOF重写缓冲区的目的是因为子进程在进行AOF文件重写期间,服务器进程还在继续处理命令请求,
而新的命令可能会对现有的数据库进行修改,从而使得服务器当前的数据库数据和重写后的AOF文件所
保存的数据库数据不一致。
子进程完成AOF重写工作,向父进程发送一个信号,父进程在接收到该信号后,会执行以下操作:
1.将AOF重写缓冲区中的所有内容写入到新AOF文件中,这样就保证了新AOF文件所保存的数据库数据和服务器当前的数据库数据是一致的。
2.对新的AOF文件进行改名,原子地覆盖现有的AOF文件,完成新旧两个AOF文件的替换。
Redis提供了BGREWRITEAOF命令来执行以上步骤,如下图所示:
执行完成后,打开appendonly.aof文件,发现保存list键的命令从六条变为了一条:
除了手动执行BGREWRITEAOF命令外,Redis还提供了2个配置项用来自动执行BGREWRITEAOF命令:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
该配置表示,当AOF文件的体积大于64MB,并且AOF文件的体积比上一次重写之后的体积大了至少一倍(100%),Redis将自动执行BGREWRITEAOF命令。
4. RDB持久化、AOF持久化的区别通过上面的讲解,我们会发现Redis提供的2种持久化方法是有区别的,可以总结为以下4点:
实现方式
文件体积
安全性
优先级
接下来一一讲解。
4.1 实现方式RDB持久化是通过将某个时间点Redis服务器存储的数据保存到RDB文件中来实现持久化的。
AOF持久化是通过将Redis服务器执行的所有写命令保存到AOF文件中来实现持久化的。
4.2 文件体积由上述实现方式可知,RDB持久化记录的是结果,AOF持久化记录的是过程,所以AOF持久化生成的AOF文件会有体积越来越大的问题,Redis提供了AOF重写功能来减小AOF文件体积。
4.3 安全性AOF持久化的安全性要比RDB持久化的安全性高,即如果发生机器故障,AOF持久化要比RDB持久化丢失的数据要少。
因为RDB持久化会丢失上次RDB持久化后写入的数据,而AOF持久化最多丢失1s之内写入的数据(使用默认everysec配置的话)。
4.4 优先级