详解redis AOF、RDB持久化方式

99 阅读6分钟

    redis作为一个内存数据库,一旦服务器断电,宕机,数据库就会被清空,为了实现持久化的能力,redis实现了两种持久化的方式,一种是AOF,另一种是RDB。这两种方式都各有特色。下面一一介绍他们。

RDB

 RDB是将数据库状态保存下来生成一个压缩的RDB文件,可以认为是对当前redis数据库的一个全量复制,这个RDB文件是持久化在磁盘的。  
RDB持久化既可以手动通过执行SAVE,BGSAVE两个命令来实现,也可以通过服务器的配置定期执行。RDB文件是如何被载入的呢,在redis  
启动的时候,就会自动去检查是否有rdb文件,如果有就会自动去载入这个RDB文件。我们上面说到了,可以通过SAVE,和BGSAVE命令来生  
成RDB文件,那么这两个命令有什么区别呢?
  SAVE:
     SAVE命令会阻塞服务器进程,在SAVE执行期间,服务器不能执行任何请求(这种方式应该没有公司能容忍吧) 
  BGSAVE:
     既然SAVE的弊端这么大,redis就搞了一个新的命令,BGSAVE,猜也能猜到,这个肯定是不阻塞服务进程的,BGSAVE 会派生出一个子  
     进程,然后由子进程负责生成这个RDB文件,服务器进程继续处理命令,那么问题来了,既然可以继续处理命令请求,那么如果client  
     再发送一个SAVE命令,这个时候,redis服务器会如何处理呢,redis为了防止产生竞争条件,会拒绝这个SAVE命令,BGSAVE命令也会  
     被拒绝。
   
对于自动保存RDB文件的条件可以由我们设置,条件格式为SAVE  m   n,在m秒对数据至少产生了n次修改,则BGSAVE命令就会被自动执行。

AOF

 RDB是通过保存数据库中的KV对来实现持久化的,而AOF是通过记录服务器所执行的写命令来实现的。AOF的实现包括三个部分,命令追加、文件写入、文件同步。
 1.命令追加
    在AOF持久化功能开启时,服务器每执行完一个写命令,就会将这个命令追加到aof_buf这个缓冲区中。
 2.文件写入
    文件写入就是写入操作系统到缓冲区,等到一定的时间或者缓冲区满了,在同步到磁盘中去。这样做到好处是提高了效率。但是万一缓冲区中的数据还没有  
    刷新到磁盘,服务器宕机了,这个时候缓冲区中的数据就丢了。鱼和熊掌不可兼得,想要性能好又想要安全是不可能的,自己需要根据业务去权衡。每次事  
    件循环完后,都会将aof_buf 中的内容写到操作系统缓冲中。
 3.文件同步
    文件同步就是决定操作系统缓冲区中的数据何时刷新到磁盘中,我们可以通过设置appendfsync的值来决定这一行为如何执行。可选择的值有三种。
     * always 每次将aof_buf写入到缓冲区时,立即将缓冲区同步到磁盘。显然这种安全性最好,但是性能较差。如果发生宕机,最多会丢一个事件循环中的数据。
     * everysenc 使用一个单独的线程,每隔一秒就同步到磁盘一次,安全和性能适中,发生宕机会丢失一秒内命令产生到数据。
     * no  由操作系统决定何时刷新到磁盘,性能最好,但是安全性最差,发生宕机会流失上一次同步后到数据。
 AOF文件重写
    AOF文件是保存所有的写命令,所以随着时间的流逝,该文件会越来越大,如果任由其增大,可能会对服务器造成影响,并且AOF文件越大,用来恢复数据的  
    时间越长,毕竟要将其中的所有命令都读出来,重新执行一遍。为了避免这些问题,redis使用了aof重写技术来缩小aof文件。aof重写是创建一个新的aof  
    文件,新旧文件的数据库状态相同,但是新的aof文件不包含任何冗余命令,所以一般新文件的大小会远远小于旧文件。下面通过一个例子来看看数据到底是  
    怎么冗余的。
    比如 redis执行了三条命令: lpush  a  b ; lpush c d; lpush e f;
    这三条命令完全可以用一条命令lpush a b c d e f来完成。
    思考一下aof重写是如何实现的,第一想法,是遍历旧的aof文件,然后分析其中的这些命令,然后重写。但是这样显然并不是一个高明的做法,  
     第一、遍历aof文件是一个耗时的操作,一般在重写的时候,aof文件都特别大了,逻辑应该比较复杂,对于同一个key的命令可能在文件中的  
          间隔比较远,所以可能要保存同一个key的内容。所以现在想一下当前旧的aof中的所有命令的重新执行的结果是什么呢,就是当前数据  
          库的状态呀。所以我们只需要读取当前数据库的状态就可以实现aof重写。aof重写是通过一个子进程来实现的,这样不会阻塞主服务器  
          进程处理命令。但是这样又出现了一个问题就是,子进程在进行aof重写时,主服务器还在处理新的命令,当子进程重写完,可能生成的  
          aof文件中的数据库状态和当前数据库的状态是不一致。当然有问题就有应对策略,redis使用了一个aof重写缓冲区,也就是当子进程开  
          始aof重写的时候,主进程每处理一条写命令,除了将它写入aof缓冲区,还要将他写入aof重写缓冲区,当aof重写完毕,将aof重写缓冲  
          区中的内容写入新的aof文件,就能使新的aof文件和当前数据库状态一致了。

优缺点对比:

RDB:  
 	优点:RDB是一个单一紧凑的文件,能非常方便的通过介质传送到其他主机,非常适合灾难恢复。
       RDB文件比AOF文件要小,且恢复速度更快,尤其在大的数据时速度更为明显。
 	缺点:可能会丢失部分数据。
AOF
  	优点:aof安全性更高,在配置合理的情况下,最少可以只丢失一个事件循环的数据。
            
 	缺点:对于相同数据库的状态来说,aof 文件体积更大,在applendfaync属性设置为always时,会比较慢。