aof相关配置
aof-rewrite-incremental-fsync yes
# aof 开关,默认是关闭的,改为yes表示开启
appendonly no
# aof的文件名,默认
appendfilename "appendonly.aof"
# aof刷数据的策略,有no/everysec/aways
appendfsync everysec
no-appendfsync-on-rewrite no
# aof超出配置大小的比例,模式是100%,可以理解为阈值
auto-aof-rewrite-percentage 100
# aof 配置的文件的大小,默认64mb
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
# rewrite 进行时候,rewrite 文件分两种格式,1. 先 用 rdb 序列化,序列化结果写入aof文件,然后期间积累的差异用追加aof命令格式 ,2 整个文件都是aof的命令追加格式
aof-use-rdb-preamble yes
appendfsync 一共有3种策略
- alays 主要有数据改动就把数据刷入磁盘,性能相对最差,但最安全
- everysec 每隔1秒刷一次数据,redis默认的,也是redis推荐的
- no 不主动刷,什么时候刷数据,取决于操作系统,大多数linux 30秒提交一次
aof写入:
在processCommand 函数里,解析出来执行命令,放入了client中
在eedAppendOnlyFile方法里主要是aof内容生成,方法就不具体列了,主要做了三件事
- 组装刚执行命令的aof内容buf,将过期时间由相对转成绝对(重点)
- 如果AOF开启的情况,将刚组装的buf放入到server.aof_buf 后
- 如果正在重写aof,将buf写到 server.aof_rewrite_buf_blocks中(在aofRewriteBufferAppend里)
这里有几个变量
- server.aof_buf aof缓冲区,用于存放每次执行命令后的aof信息
- server.aof_rewrite_buf_blocks 只要是有aof的子进程,就把新产生的命令添加上去
- server.aof_pipe_write_data_to_child aof 子进程的管道,用于将server.aof_rewrite_buf_blocks信息给子进程
在主进程执行命令后,并没有写aof文件,只是将命令拼装成了字符串,放入到了aof缓冲区server.aof_buf 中,如果有aof的子进程,将aof信息放入到server.aof_rewrite_buf_blocks 然后通过管道将该信息给到子进程。
那aof是什么时候写入到文件里呢?,别急,看下图
aof有几个场景的写入:
- 在主流程的循环体里
- 在循环执行前的beforesleep里
- 在serverCron里
- 准备停止之前调用一次
- 通过configSetCommand设置
- 主从复制
最终都是调用的flushAppendOnlyFile
- aof的写入是在beforeSleep 里,在serverCron 主要是处理延期写入或者处理写入异常
- aof通过server.aof_flush_postponed_start来延期写入,第一次将此值赋值为当前时间,写完以后置为0
- aof通过write写入文件(获取的是文件fd对应的偏移指针,顺序写)
aof重写
serverCron在执行的时候,有一个backgroundRewriteDoneHandler方法,当时就有疑问,这个重写是干啥的?
然后搜索了下,发现了这个函数rewriteAppendOnlyFileBackground
我们看下这个函数的触发的时机
先说下触发时机:
- 在周期性循环里进行
- 通过命令调用执行aof重写
- 一个是bgrewriteaofCommand
- 一个是configSetCommand
- 主从复制时触发
在serverCron里有两次调用
- ① 位置标注的调用是为了延迟补偿
- ②位置标注的每次在没有rdb和aof子进程的情况下都会进来
- redis通过server.aof_rewrite_scheduled来控制aof的延迟执行
rof重写
通过以上的代码我们可以看到:
- aof的重写过程和bgsave方式的rdb差不多的过程差不多
- aof 重写有两种模式,一种是先写rdb,再追加aof(混合模式),一种是一路aof格式
- aof在将虚拟内存空间里的数据写完以后,会通过wait轮训从管道server.aof_pipe_read_data_from_parent里获取增量更新的数据,增量更新在第一小节的时候,有个aofChildWriteDiffData处理器(通过FileEvent机制写入)
- 然后aof 子父进程发送ack确认消息
- 最后再次通过rioWrite 将ack期间追加的数据补救回来
- 最后将rof的临时文件重命名为temp-rewriteaof-bg-进程id.aof
aof后续处理
其实到这里,aof是写到文件里了,但是并没有再改到配置的文件上?
别急,我们上一篇,或者本篇aof小结那张图。
在serverCron有一个分支处理backgroundSaveDoneHandler 和backgroundRewriteDoneHandler。上一篇,我们讲过了backgroundSaveDoneHandler,另一个方法backgroundRewriteDoneHandler没有讲,翻看代码看下
在最后
- 将临时文件改成了真正配置的的aof文件
- 然后又将缓冲区aof_rewrite_buf_blocks里的数据写入到了aof文件里。
redis为什么要进行aof重写呢?
- aof记录的是所有的修改操作,随着运行越来越大;
- redis作为一个缓存数据库,很多的数据是有有效期的,可能30秒后之前的键值就无效;
- 这些失效的数据,对于aof后续的恢复来说是大部分都是执行无效的数据,会导致效能过低;
- 磁盘的的占用也是一个问题,其实rdb也是这个理;