持久化的作用

Redis是内存型数据库,如果在运行过程中断电,内存数据会丢失。但是Redis提供了持久化机制,让Redis能在意外发生后能重新恢复原有数据。

AOF持久化策略

AOF(Apend Only File)是将写操作以追加的形式写入到文件中的持久化策略。

AOF的原理

  • 当发生写操作时,就会进行追加操作记录到文件的操作(读操作不会修改数据,故不用进行对读操作追加操作日志到文件的操作)。

  • AOF具体执行步骤为:等待写操作完成 -> 追加操作记录到文件,这两个操作都是在主进程中运行的。

file

在写操作后再进行追加操作记录到文件操作的优缺点

  • 优点(对比在写操作前进行追加操作记录到文件操作):
    1. 不用阻塞当前写入操作。
    2. 避免检查带来的额外开销(如操作语法错误导致AOF文件回滚等)。
  • 缺点:
    1. 由于这两个操作都是在主进程进行,故可能会造成后续写阻塞的问题。
    2. 如果在追加写操作记录到文件过程中突然断电,则会丢失对应数据。

AOF写入磁盘的三种策略

我们先看看追加写操作到磁盘过程中经历了什么:

  1. 将AOF日志追加到AOF缓冲区。
  2. AOF缓冲区通过系统IO调用拷贝到内核缓冲区。
  3. 由内核自行将内核缓冲区的数据持久化到磁盘。

如图所示:

file

如果在持久化到硬盘前任意时刻,突然发生断电,那么未持久化到硬盘的数据将永久丢失。

为了解决这个问题,AOF提供了三种写入磁盘的策略:

  1. Always:每次写操作执行后生成日志完成,直接将内核缓冲区中的日志刷入磁盘(最安全,但是写操作密集的情况下,CPU资源占用高)

  2. Everysec:每隔1s将内核缓冲区数据刷入盘。(如果断电将丢失一秒数据,要求能容忍一定的数据丢失,CPU占用比Always策略低)

  3. No:Redis不进行主动刷盘操作,而是由内核自行进行刷盘操作。

file

然而,这三种策略无法完美解决性能与安全的需求,需要我们根据实际情况选择适当的策略。

AOF文件过大怎么办?— — AOF的重写机制

AOF文件过大,将会触发AOF重写机制。Redis会fork一个子进程,子进程中的内存数据和父进程共享,子进程在后台进行扫描操作,扫描每一项数据转变成写操作追加写入新的AOF文件。

为什么重写AOF后的文件会比原来的AOF文件小?

假如一个key执行了2次写操作,那么AOF文件中就存放着两次写操作记录,我们知道有一个操作记录是无效的,而重写AOF相当于清除无效写操作记录。所以重写AOF后的文件会比原来的AOF文件小。

当子进程进行重写AOF操作时,主进程进行数据更新,如何处理?

我们知道,当主进程fork子进程之后,父子进程共享资源数据。当如果父子进程任意进程对数据进行修改,就会发生写拷贝机制,此时被修改的数据就会变成父子各一份数据,导致父子进程数据不一致的情况。

我们知道,Redis进行重写AOF操作时,是让子进程后台进行的,主进程还是照常执行自己的任务,如果主进程再出现写操作,那么子进程是不知道这一操作的。

Redis 持久化机制插图3

针对这种情况,Reids在发送AOF重写过程中,主进程若发生写操作,则将AOF日志更新到AOF缓冲区和AOF重写缓冲区中。

Redis 持久化机制插图4

当子进程重写AOF操作完成后,会发送信号给主进程,主进程收到信号后,会将重写缓冲区中的数据更新到新的AOF文件中。


学习中的问题:为什么AOF重写过程中,主进程要将日志同时更新到AOF缓冲区和AOF更新缓冲区中呢?只更新AOF重写缓冲区不行吗?

不行,如果重写AOF失败了,重写AOF过程中主进程没有将日志更新到AOF缓冲区中,那么这段操作记录将被丢失。

RDB持久化策略

RDB(Redis Database)是将Redis内存中的数据以快照的存到磁盘中的持久化策略。

RDB原理

在RDB持久化过程中,会以快照的形式,将内存数据持久化到.rdb文件中。这种做法的好处是,对比AOF持久化,崩溃恢复速度快;坏处是备份时由于是全量备份,数据量大的时候需要备份很久。

RDB的两种策略方式

1. 在主线程进行RDB操作

可以在主线程(主进程)上直接进行RDB操作,但是如果数据非常大,备份时间就会比较久,会阻塞主线程(主进程)其他操作。

2. fork一个子进程,在子进程进行RDB操作

我们知道linux写时拷贝技术,当主进程fork出一个子进程时,子进程和主进程共享同一内存空间,假如主进程子进程任意进程对内存进行修改,就会将对应物理内存页复制一份,此时修改过的内存页子进程和父进程各执一份内存页。

此时,子进程相当于拥有了一份内存快照,由子进程进行RDB持久化。这种方式不会导致主线程(主进程)阻塞。

当然,这种方式会导致持久化过程中主进程写入操作无法被持久化。

选择RDB持久化时机

Redis可以对RDB持久化时机进行配置(持久化工作由子进程进行)。

save 900 1
save 300 10
save 60 10000

每行第一个参数save表示进行持久化操作,第二个参数是备份周期(秒),第三个参数为一个备份周期内至少要执行多少次备份。

比如第一行意思是,每隔900秒执行至少一次备份。

对比AOF持久化,RDB每次持久化工作量更大,如果频繁进行RDB持久化操作,会导致计算机资源占用过高,导致性能下降。

如果备份频率过低,面临数据更新频繁的场景,一次宕机就会丢失很多数据。

RDB和AOF的抉择

RDB还是AOF?

如果需要保证数据强一致性,AOF中的Always磁盘写入机制可以保证数据不被丢失。 AOF 日志可以以秒级的方式记录操作命令,所以宕机丢失的数据就相对更少。

但是AOF文件可能会很大。

如果希望故障后快速恢复,RDB是很好的选择。

但是RDB备份时间长,不适合频繁备份,且一旦宕机,会丢失很多数据。

Redis4.0的混合持久化

Redis4.0采用了RDB + AOF混合持久化机制,结合了RDB恢复快和AOF不会丢失数据的特点。

混合持久化在AOF重写过程,前半部分RDB持久化,备份全量数据,后半部分进行AOF持久化,备份新增数据。得出来的AOF文件,前半部分是RDB数据,后半部分是AOF数据。

Redis 持久化机制插图5

参考资料

  1. 知乎:redis的aof重写为什么要后台重写并且在期间进程的新命令要同时写到aof缓冲区和aof重写缓冲区?
  2. 小林coding:AOF
  3. 小林coding:RDB

Categories:

Tags:

还没发表评论,快来发表第一个评论吧~

发表回复