参考:
https://time.geekbang.org/column/article/271839
引言
另一种持久化方法:内存快照。所谓内存快照,就是指内存中的数据在某一个时刻的状态记录。
快照文件就称为 RDB 文件,其中,RDB 就是 Redis DataBase 的缩写。
和 AOF 相比,RDB 记录的是某一时刻的数据,并不是操作,所以,在做数据恢复时,我们可以直接把 RDB 文件读入内存,很快地完成恢复。
“哪些数据做快照”以及“做快照时数据能否修改”两大问题
对哪些数据做快照?这关系到快照的执行效率问题;
做快照时,数据还能被增删改吗?这关系到 Redis 是否被阻塞,能否同时正常处理请求。
给哪些内存数据做快照?
Redis 的数据都在内存中,为了提供所有数据的可靠性保证,它执行的是全量快照
Redis 提供了两个命令来生成 RDB 文件,分别是 save 和 bgsave。
- save:在主线程中执行,会导致阻塞;
- bgsave:创建一个子进程,专门用于写入 RDB 文件,避免了主线程的阻塞,这也是 Redis RDB 文件生成的默认配置。
快照时数据能修改吗?
Redis 就会借助操作系统提供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,正常处理写操作。
bgsave 这个操作是子进程在后台完成的,这就允许主线程同时可以修改数据。
可以每秒做一次快照吗?
虽然 bgsave 执行时不阻塞主线程,但是,如果频繁地执行全量快照,也会带来两方面的开销。
- 一方面,频繁将全量数据写入磁盘,会给磁盘带来很大压力,多个快照竞争有限的磁盘带宽。
- 另一方面,bgsave 子进程需要通过 fork 操作从主线程创建出来。虽然,子进程在创建后不会再阻塞主线程,但是,fork这个创建过程本身会阻塞主线程,而且主线程的内存越大,阻塞时间越长。
增量快照
增量快照:做了一次全量快照后,后续的快照只对修改的数据进行快照记录,这样可以避免每次全量快照的开销。
缺陷:它需要我们使用额外的元数据信息去记录哪些数据被修改了,这会带来额外的空间开销问题。
混合使用 AOF 日志和内存快照的方法
有什么方法既能利用 RDB 的快速恢复,又能以较小的开销做到尽量少丢数据呢?
Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法:
内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。
小结
这节课,我们学习了 Redis 用于避免数据丢失的内存快照方法。
这个方法的优势在于,可以快速恢复数据库,也就是只需要把 RDB 文件直接读入内存,这就避免了 AOF 需要顺序、逐一重新执行操作命令带来的低效性能问题。
不过,内存快照也有它的局限性。它拍的是一张内存的“大合影”,不可避免地会耗时耗力。虽然,Redis 设计了 bgsave 和写时复制方式,尽可能减少了内存快照对正常读写的影响,但是,频繁快照仍然是不太能接受的。
而混合使用 RDB 和 AOF,正好可以取两者之长,避两者之短,以较小的性能开销保证数据可靠性和性能。
最后,关于 AOF 和 RDB 的选择问题,我想再给你提三点建议:
- 数据不能丢失时,内存快照和 AOF 的混合使用是一个很好的选择;
- 如果允许分钟级别的数据丢失,可以只使用 RDB;
- 如果只用 AOF,优先使用 everysec 的配置选项,因为它在可靠性和性能之间取了一个平衡。每课一问