RDB 最大的问题,就是不能实时的持久化保存数据,在两次生成快照之间,实时的数据可能会随着重启而丢失AOF:append only file,类似于 MySQL 的 binlog,会把每个用户的每个操作,都记录到文件中。当 redis 重新启动的时候,就会读取 AOF 文件中的内容,用来恢复数据
AOF 的时候,RDB 就不生效了。(启动的时候就不再读取 RDB)
AOF 文件和 RDB 文件的位置一样
AOF 是一个文本文件,每次进行的操作,都会被记录到文本文件中
Redis 虽然是一个单线程的服务器,但是速度很快。为什么速度快?重要原因是其只操作内存。引入 AOF 之后,又要写内存,又要写硬盘,现在还能和之前一样快吗?
实际上是没有影响到 Redis 处理请求的速度:
AOF 是每次把新的操作写入到原有文件的末尾,属于顺序写入
AOF 机制并非是直接让工作线程把数据写入硬盘,而是先写入一个内存中的缓冲区(大大降低了写硬盘的次数),积累一波之后,再统一写入硬盘 
写硬盘的时候,写入硬盘数据的多少,对于性能影响没有很大,但是写入硬盘的次数则影响很大
如果把数据写入到缓冲区里,本质还是在内存中呀,万一这个时候,突然进程挂了,或者主机掉电了,怎么办?是不是缓冲区中的数据就丢了?
Redis 给出了一些选项,让程序猿根据实际情况来决定怎么取舍——缓冲区的刷新策略
Redis 提供了多种 AOF 缓冲区同步⽂件策略,由参数 appendfsync 控制,不同值的含义如下图:

always:频率最高,数据可靠性最高,性能最低everysec:频率较低,数据可靠性也会降低,性能会提高。每秒刷新一次(极端掉电情况,也只会损失 1s 的数据)(默认策略)no:频率最低,数据可靠性也是最低,性能最高
AOF 文件持续增长,体积越来越大,会影响到下次 Redis 启动的时间,Redis 启动的时候要读取 AOF 文件的内容
上述 AOF 中的文件,有一些是冗余的
Redis 进行操作 lpush key 111lpush key 222lpush key 333lpush key 333set key 111del keyset key 222 del keyRedis 启动时读取 AOF 内容的时候,AOF 记录了中间的过程,但 Redis 在重启的时候只关注最终结果。因此 Redis 就存在一个机制,能够针对 AOF 文件进行整理操作,这个整理就是能够剔除其中的冗余操作,并且合并一些操作,达到给 AOF 瘦身这样的效果——重写机制
比如,你每天给自己打分,买了个小本子记录
bgrewriteaof 命令auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 参数确定⾃动触发时机。 auto-aof-rewrite-min-size:表⽰触发重写时 AOF 的最⼩⽂件⼤⼩,默认为 64MB。auto-aof-rewrite-percentage:代表当前 AOF 占⽤⼤⼩相⽐较上次重写时增加的⽐例。
父进程通过 fork 创建子进程,父进程仍然负责接收请求,子进程负责针对 AOF 文件进行重写
AOF 文件中原来都有什么,只关心内存中最终的数据状态
AOF 的格式写入到一个新的 AOF 文件中即可
AOF 文件结果整理后的模样了RDB 生成一个镜像快照。只不过 RDB 这里是按照二进制的方式来生成的,AOF 重写则是按照 AOF 这里要求的文本格式来生成的(和 RDB 都是为了把当前内存中的所有数据状态记录到文件中)AOF 文件的同时,父进程仍然在不停的接收客户端的新的请求,父进程还是会把这些请求产生的 AOF 数据先写入到缓冲区,再刷新到原有的 AOF 文件里
fork 之前的状态。fork 之后新来的请求,对内存造成的修改,子进程是不知道的
aof_rewrite_buf 缓冲区,专门放 fork 之后收到的数据AOF 数据写完之后,会通过信号通知一下父进程,父进程再把 aof_rewrite_buf 缓存区中的内容也写到新 AOF 文件里AOF 文件代替旧的 AOF 文件了整个重写过程分为两个部分:
fork 之前的数据,子进程直接写入新的 AOF 文件fork 之后的数据,由父进程暂存到 aof_rewrite_buf 中,子进程完成新 AOF 文件写入之后在,再把 aof_rewrite_buf 写入到新 AOF 文件中去如果在执行 bgrewriteaof 的时候,当前 redis 已经正在进行 AOF 重写了,会怎么样呢?
AOF 重写,直接返回如果在执行 bgrewriteaof 的时候,发现当前 Redis 在生成 RDB 快照,会怎么样呢?
AOF 重写操作就会等待,等待 RDB 快照生成完毕之后,再执行 AOF 重写RDB 对于 fork 之后的新数据,就直接置之不理了。AOF 则对于 fork 之后的新数据,采取了 aof_rewriteaof_buf 缓冲区的方式来处理,为什么 RDB 不像 AOF 的机制来呢?
RDB 本身的设计理论,就是用来“定期备份”,就很难和最新的数据保持一致AOF 的理念是“实时备份”父进程 fork 完毕之后,就已经让子进程写新的 AOF 文件了,并且随着时间的推移,子进程很快就写完了新的文件,要让新的 AOF 文件代替旧的。父进程此时还在继续写这个即将消亡的旧的 AOF 文件是否还有意义?
AOF 文件内容还不完整。所以如果父进程不坚持写旧 AOF 文件,重启就没法保证数据的完整性了比如跳槽 小帅在 A 公司,干了一段时间之后,想跳槽去 B 公司。面试完了,offer 也发了,A 公司这里有一个交接时期


我们再使用 bgrewriteaof 命令手动触发重写


这是重写之前的文件内容,重写之后,AOF 文件被清空了,这个文件变成了:

AOF 本来是按照文本的方式来写入文件的,但是文本的方式写文件,后续加载的成本是比较高的。Redis 就引入了“混合持久化”的方式(结合了 AOF 和 RDB 的特点)
在 Redis 的混合持久化模式下,当执行 BGREWRITEAOF 命令时,Redis 会将当前数据库的状态进行快照,并将其保存为一个 RDB 文件(即 appendonly.aof.base.rdb)。同时,它会清理 AOF 文件,将新的数据增量写入到新的 AOF 文件(即 appendonly.aof.incr.aof)。
当 Redis 上同时存在 AOF 文件和 RDB 快照的时候,此时以谁为主?
AOF 为主,RDB 就直接被忽略了AOF 里面包含的数据比 RDB 更全