Redis之AOF重写及其实现原理

分类: Redis |
所谓“重写”其实是一个有歧义的词语,实际上,AOF重写并不需要对原有AOF文件进行任何写入和读取,它针对的是数据库中键的当前值。
假设服务器对键list执行了以下四条命令:
127.0.0.1:6379[1]> RPUSH
list 1 2 3 4
127.0.0.1:6379[1]> RPOP
list
127.0.0.1:6379[1]> LPOP
list
当前列表键list在数据库中的值就为[2,3]。要保存这个列表的当前状态,并且尽量减少使用的命令数,最简单的方式不是去AOF文件分析前面执行的三条命令,而是直接读取list键在数据库中的当前值,然后用一条RPUSH 2,3代替前面的三条命令。
根据键的类型,使用适当的写入命令来重现键的当前值,这就是AOF重写的实现原理。整个重写过程用伪代码表示如下:
=======================================================
def AOF_REWRITE(tmp_tile_name):
f.close()
========================================================
Redis不希望AOF重写会造成服务器无法处理请求,所以Redis决定将AOF重写程序放到(后台)子进程里执行。这样处理的最大好处是:
1、
2、
子进程在进行AOF重写期间,主进程还要继续处理命令请求,而新的命令可能对现有的数据进行修改,这会让当前数据库的数据和重写后的AOF文件中的数据不一致。
为了解决这个问题,Redis增加了一个AOF重写缓存,这个缓存在fork出子进程之后开始启用,Redis主进程在接到新的写命令之后,除了会将这个写命令的内容追加到现有的AOF文件之外,还会追加到这个缓存中:
http://s8/mw690/002XPXs5gy6RzHgdgxNe7&690
也就是说,子进程在执行AOF重写时,主进程需要执行以下三个工作:
1、处理命令请求;
2、将写命令追加到现有的AOF文件中;
3、将写命令追加到AOF重写缓存中。
如此可以保证:
1)、现有的AOF功能继续执行,即使AOF重写期间发生停机,也不会有任何数据丢失;
2)、所有对数据库进行修改的命令都会被记录到AOF重写缓存中。
当子进程完成对AOF文件重写之后,它会向父进程发送一个完成信号,父进程接到该完成信号之后,会调用一个信号处理函数,该函数完成以下工作:
1)、将AOF重写缓存中的内容全部写入到新的AOF文件中;
2)、对新的AOF文件进行改名,覆盖原有的AOF文件。
当“1)、将AOF重写缓存中的内容全部写入到新的AOF文件中;”执行完毕后,现有AOF文件、新的AOF文件和数据库三者的状态就完全一致了。
当“2)、对新的AOF文件进行改名,覆盖原有的AOF文件。”执行完毕后,程序就完成了新旧两个AOF文件的替换。
当这个信号处理函数执行完毕之后,主进程就可以继续像往常一样接收命令请求了。在整个AOF后台重写过程中,只有最后的“主进程写入命令到AOF缓存”和“对新的AOF文件进行改名,覆盖原有的AOF文件。”这两个步骤会造成主进程阻塞,在其他时候,AOF后台重写都不会对主进程造成阻塞,这将AOF重写对性能造成的影响降到最低。
以上阐述,就是AOF后台重写,也就是BGREWRITEAOF命令的工作原理。
触发AOF后台重写的条件
AOF重写可以由用户通过调用BGREWRITEAOF手动触发。
另外,服务器在AOF功能开启的情况下,会维持以下三个变量:
l
l
l
每次当serverCron(服务器常规操作)函数执行时,它会检查以下条件是否全部满足,如果全部满足的话,就触发自动的AOF重写操作:
1)、没有BGSAVE命令(RDB持久化)/AOF持久化在执行;
2)、没有BGREWRITEAOF在进行;
3)、当前AOF文件大小要大于server.aof_rewrite_min_size(默认为1MB),或者在redis.conf配置了auto-aof-rewrite-min-size大小;
4)、当前AOF文件大小和最后一次重写后的大小之间的比率等于或者等于指定的增长百分比(在配置文件设置了auto-aof-rewrite-percentage参数,不设置默认为100%)
如果前面三个条件都满足,并且当前AOF文件大小比最后一次AOF重写时的大小要大于指定的百分比,那么触发自动AOF重写。
小结
l
l
l