redis的数据如果服务器突然宕机,数据就会全部丢失,因此必须有一种手段来处理因为宕机而不会丢失数据,这种机制就是redis持久化。
redis持久化有两种,一种是 aof日志,一种是rdb(快照),本文介绍 rdb。
通过上一章的学习,我们知道了 aof 是 以日志记录redis的执行命令,那么在宕机的恢复的时候,如果aof文件很大,那么恢复起来也会很慢,那么有没有什么好的办法吗,那就是 RDB, RDB是以二进制的方式记录,当恢复的的时候会直接加载到内存,恢复速度会很快。
一、redis 提供了两个命令来生成 RDB 文件,分别是 save 和 bgsave。
save:在主线程中执行,会导致堵塞。
bgsave:创建一个子进程,专门用于写入 RDB 文件,避免了堵塞主线程,这也是redis RDB默认的配置项。
二、快照时数据能修改吗?
在给别人拍照时,一旦对方动了,那么这张照片就拍糊了,我们就需要重拍,所以我们当然希望对方保持不动。对于内存快照而言,我们也不希望数据“动”。
为了快照而暂停写操作,肯定是不能接受的。所以这个时候,Redis 就会借助操作系统提供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,正常处理写操作。
bgsave 是由主线程 fork 创建的,可以共享主线程的所有内存数据。
此时,如果主线程对这些数据也都是读操作(例如图中的键值对 A),那么,主线程和 bgsave 子进程相互不影响。但是,如果主线程要修改一块数据(例如图中的键值对 C),那么,这块数据就会被复制一份,生成该数据的副本。然后,bgsave 子进程会把这个副本数据写入 RDB 文件,而在这个过程中,主线程仍然可以直接修改原来的数据。
这既保证了快照的完整性,也允许主线程同时对数据进行修改,避免了对正常业务的影响。
三、可以每秒做一次快照吗?
风险
1、在进行bgsave的时候,虽然,bgsave 进行执行不堵塞主线程,但是在主线程会fork子进程,这个时候会堵塞。
2、在
增量快照:
增量快照就是指在做了一次全量快照后,后续的快照记录只对修改的数据进行快照记录,这样可以避免每次全量快照的开销。
在第一次做完全量快照后,T1 和 T2 时刻如果再做快照,我们只需要将被修改的数据写入快照文件就行。但是,这么做的前提是,我们需要记住哪些数据被修改了。你可不要小瞧这个“记住”功能,它需要我们使用额外的元数据信息去记录哪些数据被修改了,这会带来额外的空间开销问题。这对于内存资源宝贵的 Redis 来说,有些得不偿失。
到这里,你可以发现,虽然跟 AOF 相比,快照的恢复速度快,但是,快照的频率不好把握,如果频率太低,两次快照间一旦宕机,就可能有比较多的数据丢失。如果频率太高,又会产生额外开销,那么,还有什么方法既能利用 RDB 的快速恢复,又能以较小的开销做到尽量少丢数据呢?
Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。简单来说,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。
配置项: aof-use-rdb-preamble yes
这样一来,快照不用很频繁地执行,这就避免了频繁 fork 对主线程的影响。而且,AOF 日志也只用记录两次快照间的操作,也就是说,不需要记录所有操作了,因此,就不会出现文件过大的情况了,也可以避免重写开销。
总结:
1、数据不能丢失时,内存快照和rdb 混合使用是一个好的办法。
2、允许分钟级别的丢失,可以使用rdb。
3、如果只用 AOF,优先使用 everysec 的配置选项,因为它在可靠性和性能之间取了一个平衡。