Redis:一文带你了解RDB

Redis:一文带你了解RDB

宕机后的Redis如何实现快速恢复?采用AOF进行故障恢复,需要对操作日志逐一执行一遍就会影响Redis的正常使用,那么有没有一种方法可以既保证可靠性,又能够在宕机时实现快速恢复?

内存快照-内存中的数据在某一时刻的状态记录,类似于当你给朋友拍照时,一张照片就能把朋友一瞬间的形象完全记录下来。

如果redis能够像照片的记录效果,将某一时刻的状态以文件的形式写入到磁盘中,即便宕机时,快照文件也不会丢失,数据的可靠性也就有了保证,快照文件即为RDB文件-Redis DataBase缩写;

拍照的时候,通常需要考虑两个问题:

  • 如何取景?打算把哪些人、哪些物拍到照片中;
  • 按快门前,人不能动,否则照片就会模糊;

内存快照,相当于给数据拍照片,需要考虑两个问题:

  • 对哪些数据执行快照,关系到快照的执行效率问题;
  • 做快照时,数据还能CRUD吗?Redis是否被阻塞,能否正常处理请求?

给哪些内存数据执行快照?

Redis为了提供保证所有数据的可靠性,需要执行全量快照,类似于100个人拍合影,将所有人都拍进照片里,好处是记录所有的数据到磁盘,那么带来的问题就是全量数据越多,RDB文件就越大,往磁盘上写数据的时间开销就越大。

Redis而言,它的单线程模型就决定了,我们要尽量避免所有会阻塞主线程的操作。Redis提供了两个命令来生成RDB文件,分别是save和bgsave。

  • save:在主线程中执行,会导致阻塞;
  • bgsave:创建一个子进程,专门用于写入RDB文件,避免了主线程的阻塞,这也是Redis RDB文件生成的默认配置。

快照时数据能修改吗?

在给别人拍照时,一旦对方动了,那么这张照片就拍糊了,我们就需要重拍,所以我们当然希望对方保持不动。对于内存快照而言,我们也不希望数据“动”。

如果快照执行期间数据不能被修改,是会有潜在问题的。Redis不能处理对这些数据的写操作,无疑就会给业务服务带来巨大的影响。bgsave可以避免阻塞,但是其职能处理读操作,不能修改正在执行快照的数据。

为了快照暂停写操作是不能够接受的,Redis就会借助操作系统提供的写时复制技术**(Copy-On-Write, COW)**,在执行快照的同时,正常处理写操作。

bgsave子进程是由主线程fork生成的,可以共享主线程的所有内存数据。bgsave子进程运行后,开始读取主线程的内存数据,并把它们写入RDB文件。

如果主线程对这些数据也都是读操作(例如图中的键值对A),那么,主线程和bgsave子进程相互不影响。但是,如果主线程要修改一块数据(例如图中的键值对C),那么,这块数据就会被复制一份,生成该数据的副本。然后,bgsave子进程会把这个副本数据写入RDB文件,而在这个过程中,主线程仍然可以直接修改原来的数据。

Redis:一文带你了解RDB
Redis会使用bgsave对当前内存中的所有数据做快照,这个操作是子进程在后台完成的,这就允许主线程同时可以修改数据。这时就需要考虑多久做一次快照?

多久做一次快照?

快照的间隔时间变得很短,即使某一时刻发生宕机了,因为上一时刻快照刚执行,丢失的数据也不会太多。但是,这其中的快照间隔时间就很关键了。

虽然bgsave执行时不阻塞主线程,但是,如果频繁地执行全量快照,也会带来两方面的开销

  • 频繁将全量数据写入磁盘会给磁盘带来很大的压力,多个快照竞争有限的磁盘带宽,前一个快照还没有做完,后一个又开始做了,容易造成恶性循环。
  • bgsave子进程需要通过fork操作从主线程创建出来。虽然,子进程在创建后不会再阻塞主线程,但是,fork这个创建过程本身会阻塞主线程,而且主线程的内存越大,阻塞时间越长。如果频繁fork出bgsave子进程,这就会频繁阻塞主线程了。

增量快照
所谓增量快照,就是指,做了一次全量快照后,后续的快照只对修改的数据进行快照记录,这样可以避免每次全量快照的开销。在第一次做完全量快照后,T1和T2时刻如果再做快照,我们只需要将被修改的数据写入快照文件就行。但是,这么做的前提是,我们需要记住哪些数据被修改了。你可不要小瞧这个“记住”功能,它需要我们使用额外的元数据信息去记录哪些数据被修改了,这会带来额外的空间开销问题。如下图所示:

Redis:一文带你了解RDB
Redis 4.0中提出了一个混合使用AOF日志和内存快照的方法。简单来说,内存快照以一定的频率执行,在两次快照之间,使用AOF日志记录这期间的所有命令操作。

这样一来,快照不用很频繁地执行,这就避免了频繁fork对主线程的影响。而且,AOF日志也只用记录两次快照间的操作,也就是说,不需要记录所有操作了,因此,就不会出现文件过大的情况了,也可以避免重写开销。

如下图所示,T1和T2时刻的修改,用AOF日志记录,等到第二次做全量快照时,就可以清空AOF日志,因为此时的修改都已经记录到快照中了,恢复时就不再用日志了。

Redis:一文带你了解RDB
这个方法既能享受到RDB文件快速恢复的好处,又能享受到AOF只记录操作命令的简单优势。

内存快照的局限性就是在于其记录的是全量数据,耗时耗力。虽然Redis采用了bgsave和写时复制的方式,尽可能的减少了内存快照对正常读写的影响,但是频繁快照是不能够接受的。混合使用RDB和AOF,正好可以取两者之长,避两者之短,以较小的性能开销保证数据可靠性和性能。

对于AOF和RDB的选择问题,可以参考以下几点:

  • 数据不能丢失时,内存快照和AOF的混合使用是一个很好的选择;
  • 如果允许分钟级别的数据丢失,可以只使用RDB;
  • 如果只使用AOF,优先使用everysec的配置选项,其在可靠性和性能之间取了一个平衡;

参考文献

1、极客时间-Redis核心技术与实战;

上一篇:Redis持久化锦囊在手,再也不会担心数据丢失了


下一篇:Redis如何实现主从复制