当前位置: 首页 > article >正文

【Redis】Redis RDB和AOF持久化介绍

目录

1. RDB

1.1 触发机制

1.2 流程说明

1.3 RDB 文件的处理

1.4 RDB 的优缺点

2. AOF

2.1 使用 AOF

2.2 命令写入

2.3 文件同步

2.4 重写机制

2.5 启动时数据恢复

3. 重点回顾


Redis 支持 RDB 和 AOF 两种持久化机制,持久化功能有效地避免因进程退出造成数据丢失问题,
当下次重启时利用之前持久化的文件即可实现数据恢复。本章内容:

• 介绍 RDB、AOF 的配置和运行流程,以及控制持久化的命令,如 bgsave 和bgrewriteaof。

• 对常见持久化问题进行分析定位和优化。

1. RDB

RDB 持久化是把当前进程数据生成快照保存到硬盘的过程,触发 RDB 持久化过程分为手动触发和
自动触发。

1.1 触发机制

手动触发分别对应 save 和 bgsave 命令:

save 命令:阻塞当前 Redis 服务器,直到 RDB 过程完成为止,对于内存比较大的实例造成长时间阻塞,基本不采用。

bgsave 命令:Redis 进程执行 fork 操作创建子进程,RDB 持久化过程由子进程负责,完成后自动结束。阻塞只发生在 fork 阶段,一般时间很短。

Redis 内部的所有涉及 RDB 的操作都采用类似 bgsave 的方式。

除了手动触发之外,Redis 运行自动触发 RDB 持久化机制,这个触发机制才是在实战中有价值的。

1. 使用 save 配置。如 "save m n" 表示 m 秒内数据集发生了 n 次修改,自动 RDB 持久化。

下面是redis.conf配置文件中的配置内容:

# Save the DB on disk:
#
#   save <seconds> <changes>
#
#   Will save the DB if both the given number of seconds and the given
#   number of write operations against the DB occurred.
#
#   In the example below the behavior will be to save:
#   after 900 sec (15 min) if at least 1 key changed
#   after 300 sec (5 min) if at least 10 keys changed
#   after 60 sec if at least 10000 keys changed
#
#   Note: you can disable saving completely by commenting out all "save" lines.
#
#   It is also possible to remove all the previously configured save
#   points by adding a save directive with a single empty string argument
#   like in the following example:
#
#   save ""

save 900 1
save 300 10
save 60 10000

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

3. 执行 shutdown 命令关闭 Redis 时,执行 RDB 持久化。

1.2 流程说明

bgsave 是主流的 RDB 持久化方式,可以根据下图了解它的运作流程。

1. 执行 bgsave 命令,Redis 父进程判断当前进是否存在其他正在执行的子进程,如 RDB/AOF 子进程,如果存在 bgsave 命令直接返回。

2. 父进程执行 fork 创建子进程,fork 过程中父进程会阻塞,通过 info stats 命令查看latest_fork_usec 选项,可以获取最近一次 fork 操作的耗时,单位为微秒。

3. 父进程 fork 完成后,bgsave 命令返回 "Background saving started" 信息并不再阻塞父进程,可
以继续响应其他命令。

4. 子进程创建 RDB 文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。执行 lastsave 命令可以获取最后一次生成 RDB 的时间,对应 info 统计的 rdb_last_save_time 选
项。

5. 进程发送信号给父进程表示完成,父进程更新统计信息。

1.3 RDB 文件的处理

保存:RDB 文件保存再 dir 配置指定的目录(默认 /var/lib/redis/)下,文件名通过 dbfilename
配置(默认 dump.rdb)指定。可以通过执行 config set dir {newDir} 和 config set dbfilename
{newFilename} 运行期间动态执行,当下次运行时 RDB 文件会保存到新目录。

root@VM-4-3-ubuntu:/var/lib/redis# ls
appendonly.aof  dump.rdb

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

💡 虽然压缩 RDB 会消耗 CPU,但可以大幅降低文件的体积,方便保存到硬盘或通过网络发送到从节点,因此建议开启。

校验:如果 Redis 启动时加载到损坏的 RDB 文件会拒绝启动。这时可以使用 Redis 提供的 redischeck-dump 工具检测 RDB 文件并获取对应的错误报告。

dump.rdb 文件中的内容(二进制乱码):

REDIS0009ú      redis-ver^F6.0.16ú
redis-bitsÀ@ú^EctimeÂ^R<91>_gú^Hused-memÂp\^L^@ú^Laof-preambleÀ^@þ^@û^C^@^L^Ezset1^Y^Y^@^@^@^V^@^@^@^D^@^@^Cone^Eò^B^Ctwo^Eóÿ^L^Cout""^@^@^@^_^@^@^@^F^@^@^Cone^Eö^B^Ethree^Gú^B^Ctwo^Eûÿ^L^Ezset2""^@^@^@^_^@^@^@^F^@^@^Cone^Eò^B^Ctwo^Eó^B^Ethree^Gôÿÿ<9d>ѬCÙp<93>ü

1.4 RDB 的优缺点

• RDB 是一个紧凑压缩的二进制文件,代表 Redis 在某个时间点上的数据快照。非常适用于备份,全量复制等场景。比如每 6 小时执行 bgsave 备份,并把 RDB 文件复制到远程机器或者文件系统中(如 hdfs)用于灾备。

• Redis 加载 RDB 恢复数据远远快于 AOF 的方式。

• RDB 方式数据没办法做到实时持久化 / 秒级持久化。因为 bgsave 每次运行都要执行 fork 创建子进程,属于重量级操作,频繁执行成本过高。

• RDB 文件使用特定二进制格式保存,Redis 版本演进过程中有多个 RDB 版本,兼容性可能有风
险。

2. AOF

AOF(Append Only File)持久化:以独立日志的方式记录每次写命令,重启时再重新执行 AOF
文件中的命令达到恢复数据的目的。AOF 的主要作用是解决了数据持久化的实时性,目前已经是
Redis 持久化的主流方式。理解掌握好 AOF 持久化机制对我们兼顾数据安全性和性能非常有帮助。

2.1 使用 AOF

开启 AOF 功能需要设置配置:appendonly yes,默认不开启。AOF 文件名通过appendfilename 配置(默认是 appendonly.aof)设置。保存目录同 RDB 持久化方式一致,通过 dir配置指定。

AOF 的工作流程操作:命令写入(append)、文件同步(sync)、文件重写(rewrite)、重启加载(load),如图所示。

1. 所有的写入命令会追加到 aof_buf(缓冲区)中。

2. AOF 缓冲区根据对应的策略向硬盘做同步操作。

3. 随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。

4. 当 Redis 服务器启动时,可以加载 AOF 文件进行数据恢复。

2.2 命令写入

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

*3\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n

此处遵守 Redis 格式协议,Redis 选择文本协议可能的原因:文本协议具备较好的兼容性;实现简单;具备可读性。

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

2.3 文件同步

Redis 提供了多种 AOF 缓冲区同步文件策略,由参数 appendfsync 控制,不同值的含义如表所示。

系统调用 write 和 fsync 说明:

•  write 操作会触发延迟写(delayed write)机制。Linux 在内核提供页缓冲区用来提供硬盘 IO 性
能。write 操作在写入系统缓冲区后立即返回。同步硬盘操作依赖于系统调度机制,例如:缓冲区
页空间写满或达到特定时间周期。同步文件之前,如果此时系统故障宕机,缓冲区内数据将丢失。

•  Fsync 针对单个文件操作,做强制硬盘同步,fsync 将阻塞直到数据写入到硬盘。

•  配置为 always 时,每次写入都要同步 AOF 文件,性能很差,在一般的 SATA 硬盘上,只能支持大约几百 TPS 写入。除非是非常重要的数据,否则不建议配置。

•  配置为 no 时,由于操作系统同步策略不可控,虽然提高了性能,但数据丢失风险大增,除非数据重要程度很低,一般不建议配置。

•  配置为 everysec,是默认配置,也是推荐配置,兼顾了数据安全性和性能。理论上最多丢失 1 秒的数据。

2.4 重写机制

随着命令不断写入 AOF,文件会越来越大,为了解决这个问题,Redis 引入 AOF 重写机制压缩文
件体积。AOF 文件重写是把 Redis 进程内的数据转化为写命令同步到新的 AOF 文件。

重写后的 AOF 为什么可以变小?有如下原因:

•  进程内已超时的数据不再写入文件。

•  旧的 AOF 中的无效命令,例如 del、hdel、srem 等重写后将会删除,只需要保留数据的最终版
本。

•  多条写操作合并为一条,例如 lpush list a、lpush list b、lpush list 从可以合并为 lpush list a b
c。

较小的 AOF 文件一方面降低了硬盘空间占用,一方面可以提升启动 Redis 时数据恢复的速度。

AOF 重写过程可以手动触发和自动触发:

•  手动触发:调用 bgrewriteaof 命令。

•  自动触发:根据 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 参数确定自动触发时
机。

  • auto-aof-rewrite-min-size:表示触发重写时 AOF 的最小文件大小,默认为 64MB。
  • auto-aof-rewrite-percentage:代表当前 AOF 占用大小相比较上次重写时增加的比例。

当触发 AOF 重写时,下图介绍它的运行流程。

1. 执行 AOF 重写请求。

如果当前进程正在执行 AOF 重写,请求不执行。如果当前进程正在执行 bgsave 操作,重写命令
延迟到 bgsave 完成之后再执行。

2. 父进程执行 fork 创建子进程。

3. 重写

  • a. 主进程 fork 之后,继续响应其他命令。所有修改操作写入 AOF 缓冲区并根据 appendfsync 策略同步到硬盘,保证旧 AOF 文件机制正确。
  • b. 子进程只有 fork 之前的所有内存信息,父进程中需要将 fork 之后这段时间的修改操作写入AOF 重写缓冲区中。

4. 子进程根据内存快照,将命令合并到新的 AOF 文件中。

5. 子进程完成重写

  • a. 新文件写入后,子进程发送信号给父进程。
  • b. 父进程把 AOF重写缓冲区内临时保存的命令追加到新 AOF 文件中。
  • c. 用新 AOF 文件替换老 AOF 文件。

2.5 启动时数据恢复

当 Redis 启动时,会根据 RDB 和 AOF 文件的内容,进行数据恢复,如图 4-4 所示。

3. 重点回顾

1. Redis 提供了两种持久化方案:RDB 和 AOF。

2. RDB 视为内存的快照,产生的内容更为紧凑,占用空间较小,恢复时速度更快。但产生 RDB 的开销较大,不适合进行实时持久化,一般用于冷备和主从复制。

3. AOF 视为对修改命令保存,在恢复时需要重放命令。并且有重写机制来定期压缩 AOF 文件。

4. RDB 和 AOF 都使用 fork 创建子进程,利用 Linux 子进程拥有父进程内存快照的特点进行持久化,尽可能不影响主进程继续处理后续命令。


http://www.kler.cn/a/448862.html

相关文章:

  • 在Visual Studio 2022中配置C++计算机视觉库Opencv
  • 门户系统需要压测吗?以及门户系统如何压力测试?
  • 解析在OceanBase创建分区的常见问题|OceanBase 用户问题精粹
  • [Xshell] Xshell的下载安装使用、连接linux、 上传文件到linux系统-详解(附下载链接)
  • Linux 中 grep、sed、awk 命令
  • vue iframe进行父子页面通信并切换URL
  • go中常用的处理json的库
  • c++的类中的私有成员变量是否可以在cpp文件中再定义一次
  • Redis篇--常见问题篇2--缓存雪崩(过期时间分散,缓存预热,多级缓存)
  • Docker基础命令实战
  • whisper实时语音转文字
  • Java中使用四叶天动态代理IP构建ip代理池,实现httpClient和Jsoup代理ip爬虫
  • 梳理你的思路(从OOP到架构设计)_设计模式Template Method模式
  • Vue(二)
  • MATLAB绘图基础12:地理信息可视化
  • 1222面经
  • 【Go】Go数据类型详解—指针
  • LeetCode 26. 删除有序数组中的重复项 (C++实现)
  • 工具环境 | 工具准备
  • SSM 架构 Vue 赋能:WEB 开放性实验室智能管理系统
  • harmony UI组件学习(1)
  • 实验13 C语言连接和操作MySQL数据库
  • springboot453工资信息管理系统(论文+源码)_kaic
  • 解决Vmware虚拟机系统镜像无法解析DNS
  • 【Java基础面试题034】Java泛型擦除是什么?
  • 基于大语言模型的多代理下一代制造系统能灵活动态管理制造资源的高效调度方法