完全搞懂Redis持久化之AOF原理

为何须要持久化,以及Redis持久化的RDB方式在这篇文章讲的已经很透彻了,足以吊打面试官了。并且此篇内容须要RDB文章的内容支持,因此建议先看下完全搞懂Redis持久化之RDB原理mysql

1、什么是AOF

它也是Redis持久化的重要手段之一,aof-》Append Only File,只追加文件,也就是每次处理完请求命令后都会将此命令追加到aof文件的末尾。而RDB是压缩成二进制等时机开子进程去干这件事。web

2、优缺点

一、优势

  • 持久化的速度快,由于每次都只是追加,rdb每次都全量持久化
  • 数据相对更可靠,丢失少,因能够配置每秒持久化、每一个命令执行完就持久化

二、缺点

  • 灾难性恢复的时候过慢,由于aof每次都只追加原命令,致使aof文件过大,可是后面会rewrite,可是相对于rdb也是慢的。
  • 会对主进程对外提供请求的效率形成影响,接收请求、处理请求、写aof文件这三步是串行原子执行的。而非异步多线程执行的。Redis单线程!

3、AOF原理

一、基础原理

就是每次都在aof文件后面追加命令。他与主进程收到请求、处理请求是串行化的,而非异步并行的。图示以下
在这里插入图片描述
因此aof的频率高的话绝逼会对Redis带来性能影响,由于每次都是刷盘操做。跟mysql同样了。Redis每次都是先将命令放到缓冲区,而后根据具体策略(每秒/每条指令/缓冲区满)进行刷盘操做。若是配置的always,那么就是典型阻塞,若是是sec,每秒的话,那么会开一个同步线程去每秒进行刷盘操做,对主线程影响稍小。面试

二、额外扩展

其实Redis每次在写入AOF缓冲区以前,他都会调用flushAppendOnlyFile(),判断是否须要将AOF缓冲区的内容写入和同步到AOF文件中。这个决策是由配置文件的三个策略来控制的redis

  • always
  • everysec
  • no

4、REWRITE

一、为何要rewrite?

好比我有业务很简单,就来回delete set 同一个key。就这个业务运行了10年,那么aof文件将记录无数个delete k1, set k1 xxx。其实都是重复的,可是我aof每次都追加,文件变成了1T大小。这时候Redis宕机了,要恢复,你想一想1TB大小的aof文件去恢复,累死了。最主要的是1TB大小只记录了两个命令,因此压缩其实就是来处理这件事的。sql

二、4.0版本以前的rewrite

Redis4.0以前和Redis4.0的rewrite(重写)方式不同,Redis4.0以前就是将aof文件中重复的命令给去掉。保留最新的命令。进而减小aof文件大小。好比编程

set k1 123
set k1 345
del k1
set k1 789

通过rewrite后(Redis4.0以前),只会变成以下微信

set k1 789

三、4.0版本以及以后的rewrite

4.0以前的作法效率非常低下,须要逐条命令对比。4.0开始的rewrite支持混合模式(也是就是rdb和aof一块儿用),直接将rdb持久化的方式来操做将二进制内容覆盖到aof文件中(rdb是二进制,因此很小),而后再有写入的话仍是继续append追加到文件原始命令,等下次文件过大的时候再次rewrite(仍是按照rdb持久化的方式将内容覆盖到aof中)。可是这种模式也是配置的,默认是开,也能够关闭。多线程

四、rewrite触发条件

一、手动触发

  • 客户端执行bgrewriteaof命令

二、自动触发

经过如下两个配置协做触发app

  • auto-aof-rewrite-min-size

AOF文件最小重写大小,只有当AOF文件大小大于该值时候才可能重写,4.0默认配置64mb。异步

  • auto-aof-rewrite-percentage

当前AOF文件大小和最后一次重写后的大小之间的比率等于或者等于指定的增加百分比,如100表明当前AOF文件是上次重写的两倍时候才重写。

三、触发知足条件

  • 没有BGSAVE命令(RDB持久化)/AOF持久化在执行
  • 没有BGREWRITEAOF在进行;

前两点也就是说只容许同时fork()一个子进程出来干活。

  • 当前AOF文件大小要大于server.aof_rewrite_min_size的值;
  • 当前AOF文件大小和最后一次重写后的大小之间的比率等于或者大于指定的增加百分比(auto-aof-rewrite-percentage参数)

五、rewrite原理

4.0以前版本的,和4.0以及以后关闭混合模式的状况下。
在这里插入图片描述

  • aof_rewrite_buf:rewrite(重写)缓冲区、aof_buf:写命令存放的缓冲区
  • 开始bgrewriteaof的时候,判断当前有没有bgsave/bgrewriteaof在执行,如有,则不执行,这个再rdb篇幅也有提到,以及下面不少fork()知识在rdb都有提到。完全搞懂Redis持久化之RDB原理
  • 主进程fork()出子进程,在执行fork()这个方法的时候是阻塞的,子进程建立完毕后就不阻塞了
  • 主进程fork完子进程后,主进程能继续接收客户端的请求,全部写命令依然是写入AOF文件缓冲区并根据配置文件的策略同步到磁盘的。
  • 由于fork的子进程仅仅共享主进程fork()时的内存,后期主进程在更改内存数据,子进程是不可见的。所以Redis采起重写缓冲区(aof_rewite_buf)保存fork以后的客户端请求。防止新AOF文件生成期间丢失主进程执行的新命令所生成的数据。因此此时客户端的写请求不只仅写入原来的aof_buf缓冲区,还写入了重写缓冲区。这就是我为何用深蓝色的框给他两框到一块儿的缘由。
  • 子进程经过内存快照的形式,开始生成新的aof文件。
  • 新aof文件生成完后,子进程向主进程发信号。
  • 主进程收到信号后,会把重写缓冲区(aof_rewite_buf)中的数据写入到新的AOF文件(主要是避免这部分数据丢失)
  • 使用新的AOF文件覆盖旧的AOF文件,且标记AOF重写完成。

5、RDB-AOF混合持久化

redis4.0以后才支持,默认开启

一、优势

混合持久化结合了RDB持久化 和 AOF 持久化的优势,采起了rdb的文件小易于灾难恢复,同时结合AOF,增量的数据以AOF方式保存了,数据更少的丢失。

二、缺点

兼容性差,一旦开启了混合持久化,在4.0以前版本都不识别该aof文件,同时因为前部分是RDB格式,须要专业的工具来阅读,由于是二进制,因此阅读性较差。

三、原理

须要先掌握完全搞懂Redis持久化之RDB原理和此篇幅的aof

混合持久化也是经过bgrewriteaof完成的,因此基本流程和上述同样。不一样的是当开启混合模式时,fork出的子进程先将共享的内存副本全量以RDB的方式写入aof。这样提升了速度也极大的缩小了aof文件(毕竟都是二进制)。写完仍是通知主进程,而后再将重写缓冲区的内容以AOF方式写入到文件,而后替换旧的aof文件。也就是说这种模式下的aof文件发生rewrite后前半部分是rdb格式(REDIS开头的二进制数据),后半部分是正常的aof追加的命令(重写缓冲区里的)。

四、数据恢复

会优先看是否存在aof文件,若存在则先按照aof文件恢复,由于aof毕竟比rdb全。若aof不存在,则才会查找rdb是否存在。这是默认的机制。毕竟aof文件也rewrite成rdb二进制格式,文件小,易于回复。因此redis会优先采起aof。

6、总结

此篇都是重点,废话不多。没啥可总结的。

必定要看完全搞懂Redis持久化之RDB原理会让你收获更多,还有,这只是开始,rdb&aof持久化并没完成。两者对比总结篇以及实战篇在向你我招手。

7、我的公众号

微信公众号【Java码农社区】
在这里插入图片描述