Redis持久化策略之RDB与AOF

文章目录

  • 1.RDB
    • 1)基本介绍
    • 2)自动触发
    • 3)手动触发
    • 4)RDB文件
    • 5)优点缺点
  • 2.AOF
    • 1)基本介绍
    • 2)使用方式
    • 3)工作流程
    • 4)重写机制
    • 5)AOF文件
    • 6)优点缺点
  • 3.RDB + AOF

 我们都知道,redis 是一个基于内存的数据库。基于内存的好处是访问速度快,缺点是“不持久”——当数据库重启时内存中原先的数据全都会被清空。然而小孩子才做选择,redis 说我全都要:当插入一份新的数据时,在内存中会存储一份,在磁盘中也会存储一份(当然具体怎么写 redis 有自己的策略,从而保证足够的效率)

 当要访问数据时,直接从内存中获取;当 redis 重启时,可以根据磁盘中的备份来恢复。虽然会消耗更多的磁盘空间,然而磁盘资源在计算机世界里可以说是最廉价的了,这样的开销并不会带来多大的成本。

 Redis官网中列出了如下四种持久化策略:

Redis持久化策略之RDB与AOF_第1张图片

1.RDB

1)基本介绍

 RDB(Redis Database)是 redis 中默认使用的持久化策略,它的思想是定期对 redis 进行一次全量备份,备份数据是二进制的方式存储的,其存储路径由配置文件 redis.conf 指定。

​ RDB持久化过程分为自动触发和手动触发,下面分别介绍

2)自动触发

自动触发有三种情况:

  1. m秒内数据集发生了n次修改则自动触发。m和n的具体数值由配置文件决定,在我当前的配置文件下有3中选项
    image-20231116143006807
     注意,m与n是并且的关系,只有同时满足才会被触发。例如上面的触发条件翻译为:距离上一次备份过去 60s 时,至少发生了 10000 次修改则触发 rdb 备份,另外两条同理。如果你想禁止自动生成 rdb 快照,你可以这样修改配置文件:save ""

  2. 从节点进行全量复制操作时,主节点自动进行RDB持久化,随后将RDB文件内容发送给从结点

  3. 执行shutdown命令关闭Redis时,执行RDB持久化。所以说正常退出 Redis 服务器前都会对当前的数据进行一次备份

3)手动触发

触发命令:

手动出发 RDB 的指令有两个:

  • save:阻塞当前 Redis 服务端,直到RDB过程完成为止。对于内存比较大的实例,可能会造成 Redis 服务端的长时间阻塞,影响正常的业务请求,因此不推荐使用
  • bgsave:Redis 通过 fork() 指令创建子进程,由子进程完成 RDB 的持久化过程。阻塞过程只会发生在 fork 阶段,但是得益于写时拷贝机制,创建子进程的时间一般很短,影响不大,因此推荐使用

执行流程:

Redis持久化策略之RDB与AOF_第2张图片

  1. 执行 bgsave 命令后,Redis 父进程会首先检查是否有正在执行 RDB/AOF 备份的子进程,如果有 bgsave 就立刻返回,间隔时间这么短,再开一个子进程备份的意义不大。

  2. 父进程执行 fork 创建子进程。fork过程中父进程可能会被阻塞,最近一次的fork操作耗时可以在redis 服务端使用 info 指令查看,单位为微秒。
    image-20231117201051431

  3. 父进程 fork() 完成后,就可以继续接受客户端的业务请求,而将备份的任务交给子进程完成

  4. 子进程会向一个临时的快照文件写入 redis 备份数据,当备份完成时,会删除历史的 dump.rdb 并将该快照文件重命名为 dump.rdb,从而保证了自始至终只有一份 rdb 备份文件

  5. 子进程通过信号通知父进程 rdb 备份工作完成

实验验证:

​ 打开 /var/lib/redis (具体路径因人而异,见配置文件)下的 dump.rdb 文件,正如我们所预期的一样,文件以二进制的形式存储,所以呈现出来的都是人眼不能识别的乱码:

image-20231116145705596

使用 stat 指令记录下此时的 innode 编号

Redis持久化策略之RDB与AOF_第3张图片

执行 bgsave 手动完成 rdb 备份时,根据 Inode 编号我们就可以发现文件已经被替换了。

Redis持久化策略之RDB与AOF_第4张图片

4)RDB文件

保存:

​ RDB文件保存在 dir 配置指定的目录(默认/var/lib/redis/)下,文件名通过 dbfilename配置(默认dump.rdb)指定。

Redis持久化策略之RDB与AOF_第5张图片

​ 可以通过执行 config set dir{newDir}config set dbfilename{newFilename} 运行期间动态执行,当下次运行时RDB文件会保存到新目录

压缩:

​ Redis默认采用 LZF 算法对生成的 RDB 文件做压缩处理,压缩后的文件远远小于内存大小,默认开启,可以通过参数 config set rdbcompression{yes|no} 动态修改

image-20231116150951730

校验:

​ dump.rdb 里面的数据不要乱改,修改后可能看不出什么影响,也可能会导致数据错误,甚至有可能导致 redis 服务端启动失败。

  • 我们手动向 dump.rdb 文件追加数据,然后重启 redis 服务端,观察结果。使用 keys * 发现似乎没什么影响

    Redis持久化策略之RDB与AOF_第6张图片

  • 我们再尝试在文件中间修改,然后重启 redis 服务端,观察结果:

    image-20231116204407470

​ 现在好了,连 redis 客户端也连不上了,看看日志文件怎么说(日志文件路径同样可以在配置文件中找到,对应 logfile 配置项)

image-20231116204656823
 日志说的很明白了,都是 RDB 文件格式不对惹的祸。当 dump.rdb 被恶意修改时,其结果是不可预期的。对此,我们可以使用 redis 提供的 rdb 文件格式检查工具进行检查:

Redis持久化策略之RDB与AOF_第7张图片

Redis持久化策略之RDB与AOF_第8张图片

5)优点缺点

优点:

  • RDB是一个紧凑压缩的二进制文件,代表Redis在某个时间点上的数据快照,非常适用于备份,全量复制等场景。非常适合灾难恢复,因为它是一个可以传输到远程数据中心的单一紧凑文件
  • RDB 持久化策略可以最大化 Redis 的性能,因为父进程从不需要执行磁盘I/O或类似操作,一切的 IO 工作都交给了子进程完成
  • 与AOF相比,RDB允许使用大数据集更快地重新启动。因为 RDB 是以二进制的方式存储数据,而 AOF 是以文本的形式记录对 redis 的各种数据操作

缺点:

  • RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行 fork 创建子进程,属于重量级操作,频繁执行成本过高。 因此如果 Redis 服务端在两次备份中间异常退出了(正常退出会自动备份),那么退出前的新插入的数据就得不到持久化
  • RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个RDB版本,兼容性可能有风险

2.AOF

1)基本介绍

 前面谈到,RDB 最大的缺点是不能实时持久化保存数据,在两次快照之间,实时数据可能会因为 Redis 异常退出而丢失。而 AOF 则可以较好的处理实时性的问题。

 AOF类似于mysql中的binlog,它会以独立日志的方式记录 Redis 服务端收到的每一条写入操作,重启时再重新执行AOF文件中的各种命令达到恢复数据的目的。 AOF 解决了数据的实时性问题,因此已经成为了 Redis 持久化的主流方式。

2)使用方式

 Redis 中默认采用的持久化策略为 RDB,开启 AOF 功能需要设置配置: appendonly yes ,当RDB 与 AOF 可以同时设置,但如果开启 AOF ,Redis 在启动时就会从 AOF 中加载数据

Redis持久化策略之RDB与AOF_第9张图片

3)工作流程

具体流程:

Redis持久化策略之RDB与AOF_第10张图片

  1. Redis 客户端输入的所有指令都会被追加到 aof_buf 缓冲区中
  2. AOF 缓冲区根据策略定期将数据刷新到磁盘
  3. 随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,以达到数据压缩的目的
  4. 当 Redis 服务器重启时,可以加载 AOF 文件进行数据恢复

缓冲区:

 AOF过程中为什么需要aof_buf这个缓冲区?Redis使用单线程响应命令,如果每次写AOF文件都直接同步硬盘,性能从内存的读写变成IO读写,必然会下降。先写入缓冲区可以有效减少IO次数。同时,Redis还可以提供三种缓冲区同步策略,让用户根据自己的需求做出合理的平衡 :

  • no:由OS控制 fsync 频率。效率最高但安全性最差
  • always:每一次写入都会立即进行 fsync 刷盘。效率最低,安全性最高
  • everysec:每秒执行一次 fsync。兼顾安全性和效率,最常使用

image-20231117161124590

 虽然缓冲中的数据在刷盘前也存在丢失的风险,但是相较于 RDB,AOF的刷新频率很快,所以你最多只会丢失 1s,甚至一行命令的数据

4)重写机制

基本认识:

 随着命令不断写入AOF,.aof 文件会越来越大,Redis 服务端重启的速度自然越来越慢。为了解决这个问题,Redis引入 AOF 重写机制来压缩文件体积。

 重写机制就是去除冗余操作,合并相同操作的过程,虽然听起来很复杂,但实现起来却很简单,因为对于 aof 文件而言,并不需要关心中间的各种过程,只关心最后 Redis 数据库的状态,因此重写的本质是将 Redis 进程内的数据转化为写命令同步到新的 AOF文件

触发条件:

AOF 重写过程有自动触发和手动触发两种方式:

  • 自动触发:触发时机由配置文件中的参数决定,两个同样是 “并且” 的关系

    • auto-aof-rewrite-min-size:表示触发重写时AOF的最小文件大小,默认为64MB

    • auto-aof-rewrite-percentage:代表当前AOF占用大小相比较上次重写时增加的比例,默认为 100%,意味着至少要是上次重写体积的两倍才触发

      image-20231117162114011

  • 手动触发:调用 bgrewriteaof 命令

重写流程:

Redis持久化策略之RDB与AOF_第11张图片

  1. 如果当前有进程已经在执行 AOF 重写,则返回一个 error。如果有进程正在执行 bgsave 命令,则 bgsave 完成后重写才会开始
  2. 父进程创建子进程,由子进程完成重写任务
  3. 父进程fork之后,继续响应其他命令:
    • 所有修改操作写入 AOF 缓冲区并根据 appendfsync 策略同步到硬盘,保证旧 AOF 文件机制正确
    • 同时 fork 之后的数据也要写一份到 aof_rewrite_buf 缓冲区中以保证数据的一致性(后面具体解释)
  4. 子进程根据内存快照,将数据以命令的形式合并到新的AOF文件中
  5. 子进程完成重写工作后:
    • 子进程向父进程发送信号,通知父进程重写工作完成
    • 父进程把 aof_rewrite_buf 内临时保存的命令追加到新 AOF 文件中
    • 用新 AOF 文件替换老的 AOF 文件 (实验方法同上)

重写缓冲区

为什么需要重写缓冲区,看下面这个例子:

时间 父进程 子进程
t1 execute command “set key1 1”
t2 execute command “set key2 2”
t3 Create subprocess, execute AOF file rewrite Start AOF file rewrite
t4 execute command “set key1 11” execute the rewrite operation
t5 execute command “set key2 22” execute the rewrite operation
t6 …… Complete AOF rewrite

 我们知道,进程具有独立性,子进程创建后就和父进程在数据上独立了,这就意味着子进程只会记录上图中 t3 时刻 Redis 内存中的数据。因此父进程额外开辟了一块缓冲区用于记录fork 后父进程收到的请求,在子进程完成重写后再将这块缓冲区追加到 new AOF 文件的结尾,就可以保证数据的一致性。

AOF缓冲区

 为什么 fork 后父进程还要向 AOF 缓冲区写入数据呢?对于安全问题,我们往往要考虑到各种极端的情况。如果子进程还没有完成重写 Redis 服务端就异常退出了,抑或是主机掉电了,那么新 AOF 文件的内容肯定是不完整的,内存中的 aof_rewrite_buf 也已经丢失,这就意味着 fork 后插入的数据都丢失了。

 因为即使 fork 后,父进程仍然要向 aof_buf 写入,并按照刷新策略定期刷新到磁盘,从而保证数据的安全

5)AOF文件

 AOF命令写入的内容直接是文本协议格式。例如set hello world这条命令,在AOF文件中会追加如下文本 :

Redis持久化策略之RDB与AOF_第12张图片

 此处遵守Redis格式协议,Redis选择文本协议可能的原因:文本协议具备较好的兼容性;实现简单;具备可读性。 对于 AOF 文件,redis 同样提供了格式检查工具 redis-check-aof,这里不再重复演示。

6)优点缺点

优点:

  • AOF 策略相比于 RDB 数据更加可靠。everysec 策略下,你最多损失 1s 的数据
  • AOF 的重写机制在保证数据安全的前提下,避免了 AOF 文件太臃肿
  • AOF 文件以文本的方式包含了各种 operations,具有较好的可读性。你甚至可以轻松的导出 AOF 文件,例如你不小心的使用 FLUSHALL 删除所有数据,你也可以根据 AOF 文件恢复出 FLUSHALL 之前的所有数据,在没有 rewrite 的前提下。

缺点:

  • AOF 文件通常比 RDB 文件体积更大
  • AOF 持久化策略通常比 RDB 策略效率低。一般来说,在fsync设置为每秒一次的情况下,性能仍然很高,而在禁用fsync的情况下即使在高负载下,它应该与RDB一样快

3.RDB + AOF

Redis引入了“混合持久化”的方式,结合了 AOF + RDB 的优点:

  • 按照 AOF 的方式记录每一个请求

    Redis持久化策略之RDB与AOF_第13张图片

  • 在触发 AOF 重写后,就把当前内存的状态按照 RDB 二进制文件的格式写入到新的 aof 文件中(对上一个文件重写后的结果)

    image-20231117212059357

  • 后续再进行操作仍然是以 aof 文本的方式追加到 aof 文件末尾

    Redis持久化策略之RDB与AOF_第14张图片

该功能默认开启,对应配置文件中的参数如下:
Redis持久化策略之RDB与AOF_第15张图片

你可能感兴趣的:(#,【Redis原理与使用】,redis,数据库)