内存快照。所谓内存快照,就是指内存中的数据在某一个时刻的状态记录。这就类似于照片,当你给朋友拍照时,一张照片就能把朋友一瞬间的形象完全记下来。
对 Redis 来说,它实现类似照片记录效果的方式,就是把某一时刻的状态以文件的形式写到磁盘上,也就是快照。这样一来,即使宕机,快照文件也不会丢失,数据的可靠性也就得到了保证。这个快照文件就称为 RDB 文件,其中,RDB 就是 Redis DataBase 的缩写。
和 AOF 相比,RDB 记录的是某一时刻的数据,并不是操作,所以,在做数据恢复时,我们可以直接把 RDB 文件读入内存,很快地完成恢复。
Redis 中的数据都在内存中,为了提供所有数据的可靠性保证,Redis 所执行的是全量快照。也就是说,把内存中的所有记录都记录在磁盘中, 这就类似于给 100 个人拍合影,把每一个人都拍进照片里。这样做的好处是,一次性记录了所有数据,一个都不少。
把内存中的全部数据都写到磁盘中,会花费很多的时间,数据量越大,写磁盘的时间就越长。
Redis 的 RDB 文件的生成会阻塞主线程吗?
Redis 提供了两个命令来生成 RDB 文件,分别是 save 和 bgsave
- save:在主线程中执行,会导致阻塞;
- bgsave:创建一个子进程,专门用于写入 RDB 文件,避免了主线程的阻塞,这也是 Redis RDB 文件生成的默认配置。
在生成快照的时候能接受新的请求吗?
答案是可以。
在生成快照的时候,内存中的数据一旦有变化,快照就跟照相一样,会产生虫影,会很模糊。
所以在生成快照的时候不能接受更新。这肯定是不能接受的,怎么办呢?
这个时候,Redis 就会借助操作系统提供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,正常处理写操作。
简单来说,bgsave 子进程是由主线程 fork 生成的,可以共享主线程的所有内存数据。
此时,如果主线程对这些数据也都是读操作(例如图中的键值对 A),那么,主线程和 bgsave 子进程相互不影响。但是,如果主线程要修改一块数据(例如图中的键值对 C),那么,这块数据就会被复制一份,生成该数据的副本(键值对 C’)。然后,主线程在这个数据副本上进行修改。同时,bgsave 子进程可以继续把原来的数据(键值对 C)写入 RDB 文件。
这既保证了快照的完整性,也允许主线程同时对数据进行修改,避免了对正常业务的影响。
接下来介绍一下增量快照
顾名思义,增量快照就是在做了一次全量快照之后,后续的快照只对修改过的数据进行快照,这样可以避免每次全量快照带来开销。
怎么知道谁修改了呢?
Redis 会有一个记录的功能,记住谁修改了,整体上是一个用空间换时间的一种方法。会占用系统内存。
相较于 AOF,快照的恢复速度快。但是如果生成快照的频率不好把握,如果频率太低,两次快照中间的数据将丢失,如果太高,将会产生额外开销。
**Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。**简单来说,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。
这样一来,快照不用很频繁的执行,然后 AOF 日志也不用记录所有的命令了,只记录两次快照中间的,因此,就不会出现文件过大的情况了,也可以避免重写开销,两全其美。