Redis AOF重写
redis除了内存快照RDB来保证数据可靠性之外,还可以使用AOF日志。
区别:RDB是将某一时刻的数据保存成一个文件,AOF则会记录接收到的所有写操作。
AOF重写函数与触发条件
AOF重写的函数是rewriteAppendOnlyFileBackground(aof.c),该函数一共会被三个函数调用。
- bgrewriteaofCommand函数 :对应bgrewriteaof 命令。执行该命令后服务会根据两个条件判断是否实际执行AOF重写。条件一:当前是否已经有AOF子进程正在执行,有则不再执行AOF重写。条件二:当前是否有正在创建的RDB子进程正在执行,有则将AOF重写设置为待调度运行,等待条件满足后运行。只有在既没有 AOF 重写子进程也没有 RDB 子进程时才会立即执行AOF重写。
- startAppendOnly函数 :对应config命令启用AOF功能。例如:“config set appendonly yes”,执行指令,AOF功能一旦启用会立即执行一次AOF重写。而在主从复制过程中,从节点AOF功能被打开,那么在加载解析RDB文件的时,AOF选项会被关闭。之后从节点RDB文件是否加载成功,都会打开AOF功能并执行一次AOF重写。
- serverCron函数 :该函数是周期行调用,在执行过程中会做两次判断决定是否执行AOF重写。条件一:检测当前是否没有 RDB 子进程和 AOF 重写子进程在执行;条件二:检测是否有 AOF 重写操作被设置为了待调度执行。检测的时间间隔为100ms。
备注:避免AOF文件过大及增加恢复时常,可以在redis.conf文件中配置两个参数, auto-aof-rewrite-percentage:AOF 文件大小超出基础大小的比例,默认值为 100%,即超出 1 倍大小。 auto-aof-rewrite-min-size:AOF 文件大小绝对值的最小值,默认为 64MB。
总结 :以上所述可总结为四个时机触发AOF重写。1、bgrewriteaof 命令被执行。2、主从复制完成 RDB 文件解析和加载(无论是否成功)。3、AOF 重写被设置为待调度执行。4、AOF 被启用,同时 AOF 文件的大小比例超出阈值,以及 AOF 文件的大小绝对值超出阈值。
AOF工作原理
Redis内部维护了一个aof_buf缓冲区,Redis服务如果发现有命令更新,先以Redis通讯协议的格式追加到aof_buf中,维护aof_buf 缓冲区的同时会执行 appendfsync 策略(写入和同步策略)。
AOF持久化的过程
- 命令追加 :更新命令追加写入到aof_buf缓冲区中。
- 文件写入 :执行write操作,写入到系统缓冲区。
- 文件同步:从系统缓冲区中同步至磁盘中。
AOF重写的底层处理逻辑
1、调用 fork 函数创建一个子进程,由子进程进行AOF重写操作。
2、调用rewriteAppendOnlyFileRio 函数,遍历每一个数据库,读取每个键值对的类型、对应的插入命令及键值对本身内容。
3、父进程禁用在AOF重写过程中发生rehash操作。
AOF同步策略
- always :该策略在每次执行更新命令时触发(Redis将aof_buf中的内容写入并同步到AOF文件中),每次发生数据变更就会立刻同步至磁盘中。
- everysec :如果上次同步时间距现在超过1分钟,则再次对AOF文件进行同步,再次同步的操作需要专门的进程负责。
- no :将aof_buf缓冲区中的内容写入到AOF中,但并不对AOF进行同步,何时同步由操作系统决定。
AOF 的重写机制
当AOF文件大小从0增长到指定大小后,会触发AOF的第一次rewrite,由fork创建子进程并携带主进程的数据副本,通过 bgRewriteAOF 命令,基于当前数据生成新的AOF文件。在此期间,Redis收到新的更新命令,会将命令暂时保存在内存中,等待新的AOF生成后,会将内存中的命令追加到新的AOF文件中。新AOF文件生成后,Redis服务会删除旧的AOF文件。
在重写期间,主IO处理的命令可能会有对当前数据做修改的命令,这会导致当前数据和AOF中数据不一致。为了维护数据一致性,Redis服务还维护了一个AOF缓冲区rewrite_buf,AOF重写过程中主进程接受到的命令会写入到rewrite_buf缓冲区中,这样主进程可以在接受命令写入aof_buf中的同时,还能将命令写入至rewrite_buf。
AOF重写与RDB创建对比
相同点:都会创建一个子进程来遍历所有的数据库,并把数据库中的每个键值(包括数据库序号、键值对类型、键值对本身等)对记录到文件中。
不同点:1、AOF 文件中是以"命令 + 键值对"的形式,来记录每个键值对的插入操作,而 RDB 文件记录的是键值对数据本身。
2、在 AOF 重写或是创建 RDB 的过程中,主进程仍然可以接收客户端写请求。
3、RDB 文件只需要记录某个时刻下数据库的所有数据,而 AOF 重写则需要把主进程收到的写操作,记录到重写的日志文件中,AOF重写的子进程与主进程之间存在通信。
备注:AOF子进程与主进程之间的通讯是通过管道(pipe)来实现的。