【Redis】内存快照:宕机了,如何实现快速恢复
Redis提供了AOF日志,如果发生宕机,执行AOF日志,对所有写操作再执行一遍,可以实现数据恢复。
但是如果日志过大,执行太多命令对性能影响较大,结果不理想。还有没有更快的恢复方法呢?
RDB内存快照
所谓内存快照,就是指内存中的数据在某一个时刻的状态记录。这就类似于照片,当你给朋友拍照时,一张照片就能把朋友一瞬间的形象完全记下来。
对 Redis 来说,它实现类似照片记录效果的方式,就是把某一时刻的状态以文件的形式写到磁盘上,也就是快照。这样一来,即使宕机,快照文件也不会丢失,数据的可靠性也就得到了保证。这个快照文件就称为 RDB 文件,其中,RDB 就是 Redis DataBase 的缩写。
和 AOF 相比,RDB 记录的是某一时刻的数据,并不是操作,所以,在做数据恢复时,我们可以直接把 RDB 文件读入内存,很快地完成恢复。听起来好像很不错,但内存快照也并不是最优选项。为什么这么说呢?
我们还要考虑两个关键问题:
- 对哪些数据做快照?这关系到快照的执行效率问题;
- 做快照时,数据还能被增删改吗?这关系到 Redis 是否被阻塞,能否同时正常处理请求。
给哪些数据做快照
针对问题一,redis采用全量快照,将内存所有数据记录到磁盘。redis提供两个方法:
- save: 主线程执行写入
- bgsave: fork子进程,专门用于写入rdb文件,避免阻塞主线程。
快照时数据能修改吗
如果是save命令,快照会阻塞主线程,使得无法再写入新数据,也就不存在修改问题。
如果是bgsave命令,子进程快照写入时,主线程依然会执行新的命令,为了确保快照的完整性,主线程只执行读操作。
不过,为了快照暂停写操作也是不能接受的。为了解决这个问题,redis借助了操作系统的写时复制技术(Copy-On-write),执行快照的同时,处理写操作。
简单来说,bgsave 子进程是由主线程 fork 生成的,可以共享主线程的所有内存数据。bgsave 子进程运行后,开始读取主线程的内存数据,并把它们写入 RDB 文件。
此时,如果主线程对这些数据也都是读操作(例如图中的键值对 A),那么,主线程和 bgsave 子进程相互不影响。但是,如果主线程要修改一块数据(例如图中的键值对 C),那么,这块数据就会被复制一份,生成该数据的副本(键值对 C’)。然后,主线程在这个数据副本上进行修改。同时,bgsave 子进程可以继续把原来的数据(键值对 C)写入 RDB 文件。
这既保证了快照的完整性,也允许主线程同时对数据进行修改,避免了对正常业务的影响。
到这里,我们就解决了对“哪些数据做快照”以及“做快照时数据能否修改”这两大问题:Redis 会使用 bgsave 对当前内存中的所有数据做快照,这个操作是子进程在后台完成的,这就允许主线程同时可以修改数据。