【Redis】持久化

1. RDB

在指定的时间间隔内将内存中的数据集快照写入磁盘, 也就是行话讲的 Snapshot 快照,它恢复时是将快照文件直接读到内存里

1.1 备份是如何执行的

Redis 会单独创建(fork)一个子进程来进行持久化,会将数据入到 一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件. 整个过程中,主进程是不进行任何 IO 操作的,这就确保了极高的性能. 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那 RDB 方式要比 AOF 方式更加的高效. RDB 的缺点是最后一次持久化后的数据可能丢失.

1.2 fork

  • Fork 的作用是复制一个与当前进程一样的进程. 新进程的所有数据(变量、环境变量、程序计数器等) 数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程
  • 在 Linux 程序中,fork() 会产生一个和父进程完全相同的子进程,但子进程在此后多会 exec 系统调用,出于效率考虑,Linux 中引入了“写时复制技术
  • 一般情况父进程和子进程会共用同一段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程

1.3 RDB 机制

RDB 其实就是把数据以快照的形式保存在磁盘上. 什么是快照呢,你可以理解成把当前时刻的数据拍成一张照片保存下来.

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

既然 RDB 机制是通过把某个时刻的所有数据生成一个快照来保存,那么就应该有一种触发机制,是实现这个过程. 对于 RDB 来说,提供了三种机制:SAVEBGSAVE、自动化. 我们分别来看一下

1.3.1 SAVE 触发方式

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

在这里插入图片描述

执行完成时候如果存在老的 RDB 文件,就把新的替代掉旧的.

我们的客户端可能都是几万或者是几十万,这种方式显然不可取.

1.3.2 BGSAVE 触发方式

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

在这里插入图片描述

具体操作是 Redis 进程执行 fork 操作创建子进程,RDB 持久化过程由子进程负责,完成后自动结束. 阻塞只发生在 fork 阶段,一般时间很短,基本上 Redis 内部所有的 RDB 操作都是采用 BGSAVE 命令,其简化流程图如下所示:

在这里插入图片描述

1.3.3 自动触发

自动触发是由我们的配置文件来完成的 (后台还是 BGSAVE 指令),在 redis.conf 配置文件中,里面有如下配置,我们可以去设置:

  • RDB 文件名

    在 redis.conf 中配置文件名称,默认为 dump.rdb

    在这里插入图片描述

  • RDB 文件位置

    RDB 文件的保存路径,也可以修改,默认为 Redis 启动时命令行所在的目录下

    在这里插入图片描述

  • 自动保存策略

    需要在配置文件中配置定时触发条件

    在这里插入图片描述

  • stop-writes-on-bgsave-error

    默认值为 yes,表示当启用了 RDB 且最后一次后台保存数据失败,Redis 是否停止接收数据.

    开启后会让用户意识到数据没有正确持久化到磁盘上,否则没有人会注意到灾难(disaster)发生了. 如果Redis重启了,那么又可以重新开始接收数据了.

    在这里插入图片描述

  • rdbcompression 压缩文件

    默认值是 yes, 对于存储到磁盘中的快照,可以设置是否进行压缩存储

    如果是的话,Redis 会采用 LZF 算法进行压缩

    在这里插入图片描述

  • rdbchecksum 检查完整性

    在存储快照后,还可以让 Redis 使用 CRC64 算法来进行数据校验,但是这样做会增加大约 10% 的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能.

    推荐开启

    在这里插入图片描述

1.4 RDB 的备份恢复

  • 关闭 Redis

  • 先把备份的 RDB 文件拷贝到工作目录下 cp dump2.rdb dump.rdb

  • 启动 Redis,备份数据会直接加载

1.5 RDB 的优势和劣势

优势:

  • RDB 文件紧凑,全量备份,非常适合用于进行备份和灾难恢复
  • 生成 RDB 文件的时候,Redis 主进程会 fork 一个子进程来处理所有保存工作,主进程不需要进行任何磁盘 IO 操作
  • RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快

劣势:

  • RDB 快照是一次全量备份,存储的是内存数据的二进制序列化形式,存储上非常紧凑. 当进行快照持久化时,会开启一个子进程专门负责快照持久化,子进程会拥有父进程的内存数据,父进程修改内存子进程不会反应出来,所以在快照持久化期间修改的数据不会被保存,可能丢失数据.

2. AOF

日志的形式来记录每个写操作(增量保存),将 Redis 执行过的所有写指令记录下来(读操作不记录), 只许追加文件但不可以改写文件,Redis 启动之初会读取该文件重新构建数据,换言之,Redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作.

2.1 AOF 持久化流程

  1. 客户端的请求写命令会被 append 追加到 AOF 缓冲区内

  2. AOF 缓冲区根据 AOF 持久化策略将操作同步到磁盘的 AOF 文件中

  3. AOF 文件大小超过重写策略或手动重写时,会对 AOF 文件 rewrite 重写,压缩 AOF 文件容量

  4. Redis 服务重启时,会重新加载 AOF 文件中的写操作达到数据恢复的目的

在这里插入图片描述

2.2 开启 AOF

AOF 默认是不开启的,需要在配置文件中配置开启

在这里插入图片描述

AOF 文件的保存路径默认和 RDB 文件一致

2.3 AOF 三种持久化策略

在这里插入图片描述

  • appendfsync always

    始终同步,每次 Redis 的写入都会立刻记入日志;性能较差但数据完整性比较好

    在这里插入图片描述

  • appendfsync everysec

    每秒同步,每秒记入日志一次,如果宕机,本秒的数据可能丢失

    在这里插入图片描述

  • appendfsync no

    Redis 不主动进行同步,把同步时机交给操作系统

    在这里插入图片描述

2.4 AOF 重写

因为 AOF 的运作方式是不断地将命令追加到文件的末尾, 所以随着写入命令的不断增加, AOF 文件的体积也会变得越来越大. 举个例子, 如果你对一个计数器调用了 100 次 INCR , 那么仅仅是为了保存这个计数器的当前值, AOF 文件就需要使用 100 条记录(entry)。然而在实际上, 只使用一条 SET 命令已经足以保存计数器的当前值了, 其余 99 条记录实际上都是多余的.

为了处理这种情况, Redis 支持一种有趣的特性: 可以在不打断服务客户端的情况下, 对 AOF 文件进行重建(rebuild)。执行 BGREWRITEAOF 命令, Redis 将生成一个新的 AOF 文件, 这个文件包含重建当前数据集所需的最少命令.

  • BGREWRITEAOF 命令

    Redis BGREWRITEAOF 命令用于异步执行一个 AOF(AppendOnly File)文件重写操作,重写会创建一个当前 AOF 文件的体积优化版本.

    即使 BGREWRITEAOF 执行失败,也不会有任何数据丢失,因为旧的 AOF 文件在 BGREWRITEAOF 成功之前不会被修改.
    AOF 重写由 Redis 自行触发,BGREWRITEAOF 仅仅用于手动触发重写操作.
    具体内容:

    • 如果一个子 Redis 是通过磁盘快照创建的,AOF 重写将会在 RDB 终止后才开始保存. 这种情况下 BGREWRITEAOF 任然会返回 OK 状态码. 从 Redis 2.6 起你可以通过 INFO 命令查看 AOF 重写执行情况.
    • 如果正在执行的 AOF 重写返回一个错误,AOF 重写将会在稍后一点的时间重新调用.

    在这里插入图片描述

  • 配置自动重写

    在这里插入图片描述

    • auto-aof-rewrite-percentage

      触发 AOF 文件执行重写的增长率,也就是文件大小增长了百分之多少就要重写

    • auto-aof-rewrite-min-size

      触发 AOF 文件执行重写的最小尺寸


no-appendfsync-on-rewrite

在这里插入图片描述

同时在执行 BGREWRITEAOF 操作和主进程写 AOF 文件的操作,两者都会操作磁盘,而 BGREWRITEAOF 往往会涉及大量磁盘操作,这样就会造成主进程在写 AOF 文件的时候出现阻塞的情形,现在 no-appendfsync-on-rewrite 参数出场了,如果该参数设置为 no,是最安全的方式,不会丢失数据,但是要忍受阻塞的问题. 如果设置为 yes 呢?这就相当于将 appendfsync 设置为 no,这说明并没有执行磁盘操作,只是写入了缓冲区,因此这样并不会造成阻塞(因为没有竞争磁盘),但是如果这个时候 Redis 挂掉,就会丢失数据. 丢失多少数据呢?在 Linux 操作系统的默认设置下,最多会丢失 30 s 的数据.


AOF 重写触发的条件:

     🍡 文件大小超过 auto-aof-rewrite-min-size

     🍡 文件大小相较上次重写完的文件大小,增长率超过 auto-aof-rewrite-percentage

AOF 重写流程

在这里插入图片描述

(1)BGREWRITEAOF 触发重写,判断是否当前有 BGSAVEBGREWRITEAOF 在运行,如果有,则等待该命令结束后再继续执行

(2)主进程 fork 出子进程执行重写操作,保证主进程不会阻塞

(3)子进程遍历 Redis 内存中数据到临时文件,客户端的写请求同时写入 aof_buf 缓冲区和 aof_rewrite_buf 重写缓冲区,保证原 AOF 文件完整以及新 AOF 文件生成期间的新的数据修改动作不会丢失

(4.1)子进程写完新的 AOF 文件后,向主进程发信号,父进程更新统计信息

(4.2)主进程把 aof_rewrite_buf 中的数据写入到新的 AOF 文件

(5)使用新的 AOF 文件覆盖旧的 AOF 文件,完成AOF重写

2.5 AOF 和 RDB 优先级

AOF 和 RDB 同时开启,系统默认取 AOF 的数据(数据不会存在丢失)

2.6 AOF 的备份恢复

AOF 的备份机制和性能虽然和 RDB 不同,但是备份和恢复的操作同 RDB 一样,都是拷贝备份文件,需要恢复时再拷贝到 Redis 工作目录下,启动系统即加载

  • 正常恢复
    • 修改默认的 appendonly no,改为 yes
    • 将有数据的 AOF 文件复制一份保存到对应目录
    • 恢复:重启 Redis 然后重新加载
  • 异常恢复
    • 修改默认的 appendonly no,改为 yes
    • 如遇到 AOF 文件损坏,通过 /usr/local/bin/redis-check-aof --fix appendonly.aof 进行恢复
    • 备份被写坏的 AOF 文件
    • 恢复:重启 Redis,然后重新加载

3. RDB 和 AOF 的抉择

3.1 RDB 和 AOF 对比

RDBAOF
启动优先级
体积
恢复速度
数据安全性丢数据根据策略决定

3.2 如何选择使用哪种持久化方式

一般来说, 如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能

如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化

有很多用户都只使用 AOF 持久化, 但并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值