文章目录

  • Redis(十五)——Redis 持久化之 RDB 机制 和 AOF 机制
  • 1、RDB(快照) 持久化
  • 2、AOF 持久化
  • 3、总结


Redis(十五)——Redis 持久化之 RDB 机制 和 AOF 机制

由于Redis的数据都存放在内存中,但是我们都知道内存的数据变化是很快的,也容易发生丢失。如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能,将数据保存到磁盘上,当redis重启后,可以从磁盘中恢复数据。

redis提供两种方式进行持久化,一种是RDB(Redis DataBase)持久化(原理是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb),另外一种是AOF(append only file)持久化(原理是将Reids的操作日志以追加的方式写入文件)。

1、RDB(快照) 持久化

什么是RDB持久化

RDB持久化是指在指定的时间间隔内将内存中的所有数据快照写入磁盘。也是默认的持久化方式,这种方式是就是把内存中数据以快照的形式保存在磁盘上写入到二进制文件中,默认的文件名为dump.rdb。

什么是快照呢,你可以理解成把当前时刻的数据拍成一张照片保存下来。

触发RDB持久化的三种机制

1、save触发方式

该命令会阻塞当前Redis服务器,执行save命令期间,Redis不能处理其他命令,直到RDB过程完成为止。具体流程如下:

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_redis

2、bgsave触发方式

执行该命令时,Redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。具体流程如下:

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_redis_02

上面两种是手动让 Redis 进行数据集保存操作。

3、自动触发

自动触发是由我们的 redis.conf 配置文件来完成的。关于自动触发的配置,在Redis(十四)——Redis 6.0.12 配置文件详解中已详细说明。

自动触发持久化,本质是 Redis 通过判断,如果满足设置的触发条件,自动执行一次 bgsave 命令。 注意:当设置多个 save m n 命令时,满足任意一个条件都会触发持久化。

RDB快照的运作方式

当 Redis 需要保存 dump.rdb 文件时, 服务器执行以下操作:

  1. Redis 调用 fork() ,同时拥有父进程和子进程。
  2. 子进程将数据集写入到一个临时 RDB 文件中。
  3. 当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。

这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益。

RDB 的优缺点

优点

  • RDB文件小,非常适合定时备份,用于灾难恢复
  • Redis加载RDB文件的速度比AOF快很多,因为RDB文件中直接存储的时内存数据,而AOF文件中存储的是一条条命令,需要重演命令。

缺点

  • RDB无法做到实时持久化,若在两次bgsave间宕机,则会丢失区间(分钟级)的增量数据,不适用于实时性要求较高的场景
  • RDB的cow机制中,fork子进程属于重量级操作,并且会阻塞redis主进程
  • 存在老版本的Redis不兼容新版本RDB格式文件的问题

测试 RDB 持久化机制

1、在 redis.conf 配置文件中配置触发 Redis的 RDB 持久化条件:这种触发机制是自动触发

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_Redis_03

2、在redis的启动目录下,可以看见已经存在一个RDB文件:dump.rdb,把它删掉:

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_AOF_04

3、设置5个key到内存中,这个时候就触发了我们配置的持久化条件

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 k4 v4 k5 v5
OK

发现在redis的启动目录下,重新出现了一个dump.rdb持久化文件

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_redis_05

4、再次删除掉 dump.rdb

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_redis_06

5、在redis 客户端执行 flushall 命令,发现在redis的启动目录下,又重新出现了一个dump.rdb持久化文件

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_AOF_07

flushall 命令用于清空 Redis 数据库,在生产环境下一定慎用,当 Redis 执行了 flushall 命令之后,则会触发自动持久化。

6、再再次删除掉 dump.rdb

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_RDB_08

7、在客户端执行shutdown命令关闭服务器:

127.0.0.1:6379> shutdown
not connected> exit

检查是否关闭,并且重新开启redis服务器:redis

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_redis_09

redis服务器已开启。

测试客户端连接:

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_持久化_10

8、客户端成功连接上redis服务器。发现在redis的启动目录下,又又重新出现了一个dump.rdb持久化文件:

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_持久化_11

在客户端执行shutdown命令关闭服务器时,那么会自动执行一次bgsave,就会以bgsave方式触发持久化。

自动触发机制的场景:

1、配置redis.conf 触发规则,自动执行持久化

2、执行shutdown命令关闭服务器,以bgsave方式触发持久化

3、执行 flushall 命令,会触发自动持久化

2、AOF 持久化

AOF 持久化

快照功能并不是非常耐久(durable): 如果 Redis 因为某些原因而造成故障停机, 那么服务器将丢失最近写入、且仍未保存到快照中的那些数据。

尽管对于某些程序来说, 数据的耐久性并不是最重要的考虑因素, 但是对于那些追求完全耐久能力(full durability)的程序来说, 快照功能就不太适用了。

从 1.1 版本开始, Redis 增加了一种完全耐久的持久化方式: AOF 持久化。

你可以通过修改配置文件来打开 AOF 功能:默认为no,表示不开启

appendonly yes

从现在开始, 每当 Redis 执行一个改变数据集的命令时(如写操作), 这个命令就会被以日志的形式记录下来(读操作不记录),并追加到 AOF 文件的末尾。AOF 文件的默认文件名为 appendonly.aof

这样的话, 当 Redis 重新启时, 程序就可以通过重新执行 AOF 文件中的内容将写指令从前到后执行一次完成数据恢复的目的。

AOF 的运作方式

AOF 重写和 RDB 创建快照一样,都巧妙地利用了写时复制机制。

以下是 AOF 重写的执行步骤:

  1. Redis 执行 fork() ,现在同时拥有父进程和子进程。
  2. 子进程开始将新 AOF 文件的内容写入到临时文件。
  3. 对于所有新执行的写入命令,父进程一边将它们累积到一个内存缓存中,一边将这些改动追加到现有 AOF 文件的末尾: 这样即使在重写的中途发生停机,现有的 AOF 文件也还是安全的。
  4. 当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有数据追加到新 AOF 文件的末尾。
  5. 搞定!现在 Redis 原子地用新文件替换旧文件,之后所有命令都会直接追加到新 AOF 文件的末尾。

AOF 持久化的优缺点

AOF 的优点

  • 使用 AOF 持久化会让 Redis 变得非常耐久(much more durable):你可以设置不同的 fsync 策略,比如无 fsync ,每秒钟一次 fsync ,或者每次执行写入命令时 fsync 。 AOF 的默认策略为每秒钟 fsync 一次,在这种配置下,Redis 仍然可以保持良好的性能,并且就算发生故障停机,也最多只会丢失一秒钟的数据( fsync 会在后台线程执行,所以主线程可以继续努力地处理命令请求)。
  • AOF 文件是一个只进行追加操作的日志文件(append only log), 因此对 AOF 文件的写入不需要进行 seek , 即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机,等等), redis-check-aof 工具也可以轻易地修复这种问题。
  • Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。
  • AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF 文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松。 导出(export) AOF 文件也非常简单: 举个例子, 如果你不小心执行了 FLUSHALL 命令, 但只要 AOF 文件未被重写, 那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL执行之前的状态。

AOF 的缺点

  • 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。
  • 根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)。
  • AOF 在过去曾经发生过这样的 bug : 因为个别命令的原因,导致 AOF 文件在重新载入时,无法将数据集恢复成保存时的原样。 (举个例子,阻塞命令 BRPOPLPUSH 就曾经引起过这样的 bug 。) 测试套件里为这种情况添加了测试: 它们会自动生成随机的、复杂的数据集, 并通过重新载入这些数据来确保一切正常。 虽然这种 bug 在 AOF 文件中并不常见, 但是对比来说, RDB 几乎是不可能出现这种 bug 的。

重写机制

AOF的方式也同时带来了另一个问题。持久化文件会变的越来越大。为了压缩aof的持久化文件。redis提供了bgrewriteaof命令。将内存中的数据以命令的方式保存到临时文件中,同时会fork出一条新进程来将文件重写。

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_持久化_12

重写aof文件的操作,并没有读取旧的aof文件,重写aof方式:基于Copy On Write,全量遍历内存中数据,然后逐个序列到新的AOF文件中(这点和快照有点类似)。因此AOF rewrite能够正确反应当前内存数据的状态。

测试AOF 持久化

1、在redis-conf 配置文件中打开 AOF 功能:

appendonly yes

2、重启redis服务

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_AOF_13

发现在redis的启动目录下。出现了一个名为 appendonly.aof 的AOF文件

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_AOF_14

修复 AOF 文件

服务器可能在程序正在对 AOF 文件进行写入时停机, 如果停机造成了 AOF 文件出错(corrupt), 那么 Redis 在重启时会拒绝载入这个 AOF 文件, 从而确保数据的一致性不会被破坏。

1、设置两个key:

127.0.0.1:6379> set k1 v1 
OK
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> get k1
"v1"

2、查看aof文件中的内容:

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_持久化_15

3、修改aof文件中的内容,让aof文件出现错误:保存退出vim

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_redis_16

4、重启 redis 服务器,客户端重新连接,发现连接失败:

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_Redis_17

这是因为检测到aof文件出现错误,因此拒绝了连接。

5、使用 Redis 附带的 redis-check-aof 程序,对原来的 AOF 文件进行修复

[root@cheng bin]# redis-check-aof --fix appendonly.aof 
0x              4d: Expected \r\n, got: 6764
AOF analyzed: size=97, ok_up_to=52, diff=45
This will shrink the AOF from 97 bytes, with 45 bytes, to 52 bytes
Continue? [y/N]: y
Successfully truncated AOF

这时候再查看一下aof文件:已经修复。发现出现错误的key已经被删除了。

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_AOF_18

修复完成后即可重新连接redis服务器。

3、总结

当 Redis 启动时, 如果 RDB 持久化和 AOF 持久化都被打开了, 那么程序会优先使用 AOF 文件来恢复数据集, 因为 AOF 文件所保存的数据通常是最完整的。

RDB和AOF到底该如何选择

选择的话,两者加一起才更好。因为两个持久化机制你明白了,剩下的就是看自己的需求了,需求不同选择的也不一定,但是通常都是结合使用。有一张图可供总结:

redis持久化 rdb 和 aof 是否都需要开启 redis持久化rdb和aof工作原理_持久化_19

参考文章:https://baijiahao.baidu.com/s?id=1654694618189745916&wfr=spider&for=pc

备份 Redis 数据

先将下面这句话铭记于心: 一定要备份你的数据库!

磁盘故障, 节点失效, 诸如此类的问题都可能让你的数据消失不见, 不进行备份是非常危险的。

Redis 对于数据备份是非常友好的, 因为你可以在服务器运行的时候对 RDB 文件进行复制: RDB 文件一旦被创建, 就不会进行任何修改。 当服务器要创建一个新的 RDB 文件时, 它先将文件的内容保存在一个临时文件里面, 当临时文件写入完毕时, 程序才使用 rename(2) 原子地用临时文件替换原来的 RDB 文件。

这也就是说, 无论何时, 复制 RDB 文件都是绝对安全的。

以下是我们的建议:

  • 创建一个定期任务(cron job), 每小时将一个 RDB 文件备份到一个文件夹, 并且每天将一个 RDB 文件备份到另一个文件夹。
  • 确保快照的备份都带有相应的日期和时间信息, 每次执行定期任务脚本时, 使用 find 命令来删除过期的快照: 比如说, 你可以保留最近 48 小时内的每小时快照, 还可以保留最近一两个月的每日快照。
  • 至少每天一次, 将 RDB 备份到你的数据中心之外, 或者至少是备份到你运行 Redis 服务器的物理机器之外。

参考文章:https://www.kancloud.cn/wizardforcel/server/save.html#save