带着问题看 redis 源码 -- rdb/aof 实现 - (sunznx) 振翅飞翔
18 September 2019

rdb/aof 是 redis 持久化的两种实现,对应的代码分别在 rdb.c 的 rdbSave 和 aof.c 的 rewriteAppendOnlyFile 里面。在博客里面,帖大段代码没啥意义,我自己都不想看,粗苗淡写的记录下一些需要注意的地方反而更有意义。接下来会以 redis 的源码实现来看看一些常见的 redis 面试题要如何解答。

redis 如何做持久化的

rdb 做全量持久化,aof 做增量持久化。
全量持久化很简单,就是直接遍历所有的 key,写到文件里面。
增量持久化的实现也很简单,redis 每执行完一条命令,就会调用一个 propagate 方法,该方法再调用 feedAppendOnlyFile 方法,这个方法的作用看名字也能看出来了。

关于 aof 重写

大家都知道,aof 重写有利于减小 aof 文件的大小,有增加 redis 恢复速率等神奇功效。一开始以为 aof 重写是使用了什么厉害的 merge 算法,一直觉得真牛逼。后来看了下源码,才发现 aof 重写只是简单的把所有的 key 全量刷新到 aof 文件。幸好实现是这么简单,不然我也看不懂。

aof 的 fsync

单单是 “写入” aof 文件是没用的。操作系统对文件的写入实际上是写在磁盘缓存上的,需要调用 fsync 来将磁盘缓存同步到磁盘上。什么时候调用 fsync 取决于 appendfsync 这个配置项( always, everysec, no )。
另外, rdb-save-incremental-fsync/aof-rewrite-incremental-fsync 这两个配置项可以设置同步一定数据之后调用一次 fsync

rdb-aof 混合持久化

rdb 的优点是恢复起来快,缺点是数据不实时。aof 正好相反,数据相对实时,但是恢复速度慢。redis 4 之后,在 aof 中融入了 rdb,即 aof 文件由两部分组成,前半段是 rdb,后半段是 aof。这个功能由 aof-use-rdb-preamble 配置项控制。虽然叫 rdb-aof 混合持久化,但是实际上还是 aof 功能。实现上只是在写 aof 日志的时候,判断有没有开启混合持久化,如果开启了就先存 rdb 格式的数据,再写入 aof 的数据。

rdb-aof 混合持久化的实现

rdb-aof 是在子进程中进行的,写 aof 的时候,首先会写 rdb,然后在写 aof。子进程并不处理 redis 命令,即子进程处理完 rdb 之后,并不知道后续的 aof 内容该怎么写。
为了解决上面这个问题,redis 会创建一些管道文件,对应的代码在 aofCreatePipes 这个函数里面,创建的管道还挺多的,反正就是为了实现上面这个同步功能。

父进程会先将增量的 aof 数据存储在 aof_rewrite_buf_blocks 这个 list 变量里面,在同步的时候,会慢慢的将 aof_rewrite_buf_blocks 的东西写到管道里面。
子进程在写的过程中,会增量的从管道里面读数据,读完之后存储到 aof_child_diff 这个 string 类型。
当子进程写完 rdb 文件,会先 append aof_child_diff ,再把剩余的 aof_rewrite_buf_blocks 的内容 append 到 aof 文件,实现混合持久化