首先我们知道AOF和RDB都是Redis持久化的方法。RDB是Redis DB,一种二进制数据格式,这样就是相当于全量保存数据快照了。AOF则是保存命令,然后恢复的时候重放命令。
AOF随着时间推移,会越来越大,因为不断往里追加命令。所以需要重写。重写解决了什么呢?就是删去了一些没用的指令,比如有一条SET a 100,然后后面又有一条SET a 200,那前一条指令就是没用的,只保留后面的即可。重写就是重新生成AOF操作命令记录的过程,还会顺带缩短重放时间。
AOF重写流程
一处拷贝
fork一个子进程,和主进程共享Redis物理内存,把这些内存里的数据写入新的AOF文件
两处缓冲
重写时候要是有新的写入命令,主进程会把他们写入到两个缓冲里——AOF缓冲和AOF重写缓冲。前者是为了给旧AOF文件,保证重写过程宕机了也能根据旧的AOF文件恢复。后者是为了给新的AOF文件,重写拷贝完内存区数据后将这部分增量数据一并写入新AOF文件。
这里很多人都有一个误区,重写时候是根据旧AOF命令来的,实际上并不是!!!
AOF重写触发后,会fork一个子进程,子进程遍历当前Redis DB中所有数据,然后再以字符串命令的形式写入新AOF文件中。等这一步执行完了后,再将AOF重写缓存区里的增量数据追加进新的AOF文件里。
全程没有拷贝AOF缓存区,也和旧AOF文件没关系!!!
混合持久化
这是对AOF重写的一个优化(redis5之后的默认方式),即将当前的数据以RDB形式写进新的AOF文件,追加的重写缓冲区数据正常写进新的AOF文件,二者共同构成新AOF文件来替代掉旧AOF文件。这样有效降低了AOF文件的体积,并且从数据恢复角度上也变快了。
值得注意的是混合持久化仍然是AOF而非RDB和AOF双开,数据恢复过程如下:
MP-AOF
MP-AOF是redis7提出来的,因为混合持久化还是有不足的,因为本质上还是没解决一些问题。
不足
主进程要写两个缓冲,aof重写缓冲和aof缓冲,这是两个重复的操作,浪费CPU和内存。同时父进程在AOF重写缓冲里的数据是通过管道传递给子进程的,然后子进程再将其追加写入AOF,这也会造成CPU的额外开销。两个相同的缓冲的内容还得写到新旧日志里,是额外的磁盘开销(因为新日志替换旧日志前还是需要刷盘的)。
做法
全程Multi-Part AOF,就是将AOF拆分为Base AOF和Incr AOF了。Base AOF是fork子进程那一刻的RDB快照(redis5就默认开启混合持久化了,redis7自然也是开启了。假设关闭的话这里还是保存的命令)。Incr AOF是重写过程中,主进程写AOF缓冲区的指令。然后有一个Manifest文件,会记录当前最新的Base AOF和Incr AOF是哪个文件,旧的会被标记然后异步删除(UNLINK)。