宕机后,Redis如何实现快速恢复?RDB

76 阅读3分钟

宕机后,Redis如何实现快速恢复?

上次学习了Redis 持久化机制AOF,今天学习另一种机制:内存快照。 用 AOF 方法进行故障恢复的时候,需要逐一把操作日志都执行一遍。如果操作日志非常多,Redis 就会恢复得很缓慢,影响到正常使用。所谓内存快照,就是指内存中的数据在某一个时刻的状态记录,在做数据恢复时,我们可以直接把 RDB 文件读入内存,很快地完成恢复。

Redis 提供了两个命令来生成 RDB 文件,分别是 save 和 bgsave。

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

快照时数据能修改吗?

为了保证快照完整性,它只能处理读操作,因为不能修改正在执行快照的数据。为了快照而暂停写操作,肯定是不能接受的。Redis 就会借助操作系统提供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,正常处理写操作。

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

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

读写复制机制.jpeg

多久做一次快照?

频繁进行全量快照会带来2方面开销

其一,频繁将全量数据写入磁盘,会给磁盘带来很大压力,前一个快照还没做完,后一个又开始了,恶性循环。

其二,bgsave 子进程需要通过 fork 操作从主线程创建出来,fork 这个创建过程本身会阻塞主线程,而且主线程的内存越大,阻塞时间越长。频繁 fork 出 bgsave 子进程,这就会频繁阻塞主线程了。

解决

增量快照,就是指,做了一次全量快照后,后续的快照只对修改的数据进行快照记录,这样可以避免每次全量快照的开销。我们需要记住哪些数据被修改了,用于记录的数据会占用内存,可能得不偿失。

Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法,也就是说:内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。快照不用很频繁地执行,这就避免了频繁 fork 对主线程的影响,AOF也不用记录所有操作,也不会出现文件过大情况。这个方法既能享受到 RDB 文件快速恢复的好处,又能享受到 AOF 只记录操作命令的简单优势,颇有点“鱼和熊掌可以兼得”的感觉。

\