前言:一旦服务器宕机,内存中的数据将全部丢失。Redis 的持久化主要有两大机制,即 AOF(Append Only File)日志和 RDB 快照。

 AOF(Append Only File)日志

AOF 日志正好相反,它是写后日志,“写后”的意思是 Redis 是先执行命令,把数据写入内存,然后才记录日志,如下图所示:

 

 

后写入

 

好处:为了避免额外的检查开销;它是在命令执行后才记录日志,所以不会阻塞当前的写操作。

坏处:有两个风险:

  a、如果刚执行完一个命令,还没有来得及记日志就宕机了,那么这个命令和相应的数据就有丢失的风险

  b、AOF 虽然避免了对当前命令的阻塞,但可能会给下一个操作带来阻塞风险。这是因为,AOF 日志也是在主线程中执行的,如果在把日志文件写入磁盘时,磁盘写压力大,就会导致写盘很慢,进而导致后续的操作也无法执行了。

针对以上风险有三种回写策略:

Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘;

Everysec,每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;

No,操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。

 

AOF重写机制

AOF重写机制指的是,对过大的AOF文件进行重写,以此来压缩AOF文件的大小。

具体的实现是:检查当前键值数据库中的键值对,记录键值对的最终状态,从而实现对 某个键值对 重复操作后产生的多条操作记录压缩成一条 的效果。进而实现压缩AOF文件的大小。

 

 

AOF日志重写为了避免阻塞主线程,导致数据库性能下降,

主进程会fork出子进程进行重写工作,fork出子进程时,子进程是会拷贝父进程的页表,即虚实映射关系,而不会拷贝物理内存。子进程复制了父进程页表,也能共享访问父进程的内存数据了,此时,类似于有了父进程的所有内存数据。

 

RDB快照

AOF记录的是操作命令,而不是实际的数据,所以,用 AOF 方法进行故障恢复的时候,需要逐一把操作日志都执行一遍。如果操作日志非常多,Redis 就会恢复得很缓慢,影响到正常使用。这当然不是理想的结果。为了快速恢复,使用RDB快照。

Redis 的数据都在内存中,为了提供所有数据的可靠性保证,它执行的是全量快照,也就是说,把内存中的所有数据都记录到磁盘中。

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

  save:在主线程中执行,会导致阻塞;

  bgsave:创建一个子进程,专门用于写入 RDB 文件,避免了主线程的阻塞,这也是 Redis RDB 文件生成的默认配置。

Redis 借助操作系统提供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,正常处理写操作。

  redis 生成rdb 时候会fork 子进程。此时的读写操作: 读:主线程和bgsave子进程互不影响。 写:被修改的数据会被复制一份为副本,bgsave 把副本数据写入rdb 文件,主线程修改原数据。

 

 

 执行快照间隔

 

 

 如果频繁地执行全量快照,也会带来两方面的开销。

  一方面,频繁将全量数据写入磁盘,会给磁盘带来很大压力,多个快照竞争有限的磁盘带宽,前一个快照还没有做完,后一个又开始做了,容易造成恶性循环。

  另一方面,bgsave 子进程需要通过 fork 操作从主线程创建出来。虽然,子进程在创建后不会再阻塞主线程,但是,fork 这个创建过程本身会阻塞主线程,而且主线程的内存越大,阻塞时间越长。(fork操作执行时,内核需要给子进程拷贝主线程的页表。如果主线程的内存大,页表也相应大,拷贝页表耗时长,会阻塞主线程。)

此时,我们可以做增量快照,所谓增量快照,就是指,做了一次全量快照后,后续的快照只对修改的数据进行快照记录,这样可以避免每次全量快照的开销。

在第一次做完全量快照后,T1 和 T2 时刻如果再做快照,我们只需要将被修改的数据写入快照文件就行。

 

混合使用 AOF 日志和内存快照

 

简单来说,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。

如下图所示,T1 和 T2 时刻的修改,用 AOF 日志记录,等到第二次做全量快照时,就可以清空 AOF 日志,因为此时的修改都已经记录到快照中了,恢复时就不再用日志了。

 

 

 

关于 AOF 和 RDB 的选择问题,我想再给你提三点建议:

数据不能丢失时,内存快照和 AOF 的混合使用是一个很好的选择;

如果允许分钟级别的数据丢失,可以只使用 RDB;

如果只用 AOF,优先使用 everysec 的配置选项,因为它在可靠性和性能之间取了一个平衡。