跟着锋哥学Java

Redis的持久化之AOF

1.什么是AOF

     AOF是AppendOnly File的缩写,是Redis系统提供了一种记录Redis操作的持久化方案,在AOF生成的文件中,将忠实记录发生在Redis中的操作,从而达到在Redis服务器重启或者当机之后,继续恢复之前数据状态的机制AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式。

2.AOF持久化原理

      AOF持久化原理:以独立日志的方式记录每次写的操作命令,redis启动之初会读取该文件重新构建数据,换句话说,redis以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),redis重启就会根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作达到恢复数据的目的

备注:只许追加日志文件内容但不可以改写文件  ,每当有一个写命令过来时,就直接保存在我们的AOF文件

   2.1AOF持久化实现

       AOF 持久化功能的实现可以分为命令追加( append )、文件写入( write )、文件同步( sync )、文件重写(rewrite)和重启加载(load)五个部分

       

   其流程如下:

  • 所有的写命令会追加到 AOF 缓冲中。

  • AOF 缓冲区根据对应的同步策略向硬盘进行同步操作。

  • 随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。

  • 当 Redis 重启时,可以加载 AOF 文件进行数据恢复。

3.AOF持久化的三种同步策略  

    Redis 每次结束一个事件循环之前,它都会调用 flushAppendOnlyFile 函数,判断是否需要将 AOF 缓存区中的内容写入和同步到 AOF 文件中。AOF持久化的有 always,everysec,no这三种同步策略

      3.1always 

     appendfsync always也就是每次修改同步:同步持久化 每次发生数据变更会被立即记录到磁盘  性能较差但数据完整性比较好在该策略下  Redis 在每个事件循环都要将 AOF 缓冲区中的所有内容写入到 AOF 文件,并且同步 AOF 文件,所以 always 的效率是 appendfsync 选项三个值当中最差的一个,但从安全性来说,也是最安全的。当发生故障停机时,AOF 持久化也只会丢失一个事件循环中所产生的命令数.

 

 

 

  3.2Everysec

      appendfsync everysec也就是每秒同步:异步操作,每秒记录如果一秒内宕机,有数据丢失,是默认的同步策略  ,在该策略下,redis 在每个事件循环都要将 AOF 缓冲区中的所有内容写入到 AOF 文件中,并且每隔一秒就要在子线程中对 AOF 文件进行一次同步,只不过整个过程都是异步的.从效率上看,该模式足够快。当发生故障停机时,只会丢失一秒钟的命令数

 

     3.3No

         appendfsync no 也就是从不同步  在这种策略下Redis 在每一个事件循环都要将 AOF 缓冲区中的所有内容写入到 AOF 文件。而 AOF 文件的同步由操作系统控制这种模式下速度最快,但是同步的时间间隔较长,出现故障时可能会丢失较多数据。 

 

 

 

 

3.4三种策略的优缺点

   1.NO策略:虽然表面上看起来提升了性能,但是会存在每次save命令执行的时候相对长时间阻塞主进程的问题。并且数据的安全性的不到保证,如果Redis服务器突然宕机,那么没有从AOF缓存中保存到硬盘中的数据都会丢失。

   2.ALWAYS策略:安全性的到了最大的保障,理论上最多丢失最后一次写操作,但是由于每个写操作都会阻塞主进程,所以Redis主进程的响应速度受到了很大的影响。

   3. EVERYSEC策略:比较建议的配置,也是Redis的默认配置,相对来说兼顾安全性和性能。

3.5三种同步策略进行比较

 

 

 

 

4.redis的重写(Rewrite)机制

    4.1重写机制介绍

      AOF采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集.可以使用命令bgrewriteaof

   4.2重写的原理

    AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),遍历新进程的内存中数据,每条记录有一条的Set语句。重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似

   4.3重写的三种触发机制

          1.手动调用 bgrewriteaof 命令,如果当前有正在运行的 rewrite 子进程,则本次rewrite 会推迟执行,否则,直接触发一次 rewrite。

          2.通过配置指令手动开启 AOF 功能,如果没有 RDB 子进程的情况下,会触发一次 rewrite,将当前数据库中的数据写入 rewrite 文件。

          3.在 Redis 定时器中,如果有需要退出执行的 rewrite 并且没有正在运行的 RDB 或者 rewrite 子进程时,触发一次或者 AOF 文件大小已经到达配置的 rewrite 条件也会自动触发一次

        4.Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M是也会触发

 4.4AOF 后台重写

          AOF 重写函数会进行大量的写入操作,调用该函数的线程将被长时间阻塞,所以 Redis 在子进程中执行 AOF 重写操作

         1.子进程进行 AOF 重写期间,Redis 进程可以继续处理客户端命令请求。

         2.子进程带有父进程的内存数据拷贝副本,在不适用锁的情况下,也可以保证数据的安全性

   在子进程进行 AOF 重启期间,Redis接收客户端命令,会对现有数据库状态进行修改,从而导致数据当前状态和 重写后的 AOF 文件所保存的数据库状态不一致。为此,Redis 设置了一个 AOF 重写缓冲区,这个缓冲区在服务器创建子进程之后开始使用,当 Redis 执行完一个写命令之后,它会同时将这个写命令发送给 AOF 缓冲区和 AOF 重写缓冲区。

 

 

 

当子进程完成 AOF 重写工作之后,它会向父进程发送一个信号,父进程在接收到该信号之后,会调用一个信号处理函数,并执行以下工作:

   1.将 AOF 重写缓冲区中的所有内容写入到新的 AOF 文件中,保证新 AOF 文件保存的数据库状态和服务器当前状态一致。

   2.对新的 AOF 文件进行改名,原子地覆盖现有 AOF 文件,完成新旧文件的替换

   3.继续处理客户端请求命令

在整个 AOF 后台重写过程中,只有信号处理函数执行时会对 Redis 主进程造成阻塞,在其他时候,AOF 后台重写都不会阻塞主进程。

 

 

 

5.AOF的劣势

   1.相同数据集的数据而言aof文件要远大于rdb文件,恢复速度慢于rdb

    2.Aof运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同

6.AOF总结

 

 

7.持久化方案总结

    1.RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储

      2.AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大.

      3.只做缓存:如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式

     4.同时开启两种持久化方式

        (1)在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.

         (2)RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?作者建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有AOF可能潜在的bug,留着作为一个万一的手段。

 8.两种持久化方案的性能建议

      1.因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件而且只要15分钟备份一次就够了,只保留save 900 1这条规则。

      2.如果Enalbe AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了.代价一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。默认超过原大小100%大小时重写可以改到适当的数值。

     3.如果不Enable AOF ,仅靠Master-Slave Replication 实现高可用性也可以能省掉一大笔IO也减少了rewrite时带来的系统波动。代价是如果Master/Slave同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载入较新的那个。新浪微博就选用了这种架构

posted on 2020-04-21 15:54  跟着锋哥学Java  阅读(858)  评论(0编辑  收藏  举报

导航