AOF文件保存的是一条一条的写命令,它的优点很明显,保存了所有的写命令,可靠性高。但是缺点也很明显,在写操作频繁的redis使用场景,AOF文件会非常大,受操作系统的限制使用AOF进行故障恢复或者全量同步,需要依次执行每一条命令,效率很低。
RDB文件是一个内存快照,记录了redis某一时刻的数据快照,而不是一条条命令。而且RDB是二进制格式保存的,无论是写磁盘还是网络传输,效率都很高,所以RDB更适合做故障恢复和全量数据同步。但是RDB的缺点是它保存的只是某一时刻的数据快照,如果redis发生故障,上一次快照和故障之间的写命令就丢失了?
如下图,执行一个快照后,key2修改了,还没来得及下一次快照,redis发生故障,key2的这一次写操作就丢失了。
混合日志
redis4.0提出了混合使用AOF和RDB快照,在AOF文件中也可以记录RDB格式的日志。这个配置参数在redis.conf文件中,最新版本中默认是开启的。
# When rewriting the AOF file, Redis is able to use an RDB preamble in the# AOF file for faster rewrites and recoveries. When this option is turned# on the rewritten AOF file is composed of two different stanzas:## [RDB file][AOF tail]## When loading Redis recognizes that the AOF file starts with the "REDIS"# string and loads the prefixed RDB file, and continues loading the AOF# tail.aof-use-rdb-preamble yes
我们看一下这个配置项上面的说明。上篇文章《redis灵魂拷问:聊一聊AOF日志重写》讲到了AOF重写,不了解的可以看一下这篇文章。AOF重写的时候会redis把AOF文件内容清空,然后记录一份RDB快照,这份数据以"REDIS"开头。记录RDB内容后,AOF文件会接着记录下次快照之前的写命令。这样就不用担心redis故障引起的数据丢失了。
在数据恢复时,redis首先会识别以"REDIS"开头的RDB日志并加载,然后再执行后面的写命令。
RDB默认配置
redis.conf中默认有下面的配置:
################################ SNAPSHOTTING ################################## Save the DB on disk:## save ## Will save the DB if both the given number of seconds and the given# number of write operations against the DB occurred.## In the example below the behaviour will be to save:# after 900 sec (15 min) if at least 1 key changed# after 300 sec (5 min) if at least 10 keys changed# after 60 sec if at least 10000 keys changed## Note: you can disable saving completely by commenting out all "save" lines.## It is also possible to remove all the previously configured save# points by adding a save directive with a single empty string argument# like in the following example:## save ""save 900 1save 300 10save 60 10000
上面的注解讲到,一个时间段内的请求数量决定了要不要写RDB日志。跟写AOF日志类似,redis主线程会fork一个bgsave子进程,fork完成之前主线程是阻塞的,而且fork之后bgsave子进程会跟主线程共用内存空间,如果这时有写请求到来,主线程只能通过CopyOnWrite来记录写数据。
RDB失败怎么办
默认情况下,如果bgsave子进程写RDB文件时出错了,redis会拒绝新的写请求。比如redis因为内存原因执行快照失败,这时就不能接受新的写请求了,如果还想继续执行写命令,就把下面的参数设置为no,但这个可能不能解决根本问题,比如内存紧张导致的快照失败。
# By default Redis will stop accepting writes if RDB snapshots are enabled# (at least one save point) and the latest background save failed.# This will make the user aware (in a hard way) that data is not persisting# on disk properly, otherwise chances are that no one will notice and some# disaster will happen.## If the background saving process will start working again Redis will# automatically allow writes again.## However if you have setup your proper monitoring of the Redis server# and persistence, you may want to disable this feature so that Redis will# continue to work as usual even if there are problems with disk,# permissions, and so forth.stop-writes-on-bgsave-error yes
总结
1.redis写RDB跟写AOF日志类似,都需要fork子进程,fork过程都要阻塞主线程,如果这时写命令到来,主线程都需要COW的方式进行写操作。
2.AOF和RDB日志混合使用大大减少了AOF文件的大小,同时提高了全量数据同步或和故障恢复的效率。
3.RDB快照执行出错,redis默认会停止接收写请求,这个可以配置,但是要确定快照失败的原因。