redis持久化:rdb快照和aof使用和区别,优点和缺点(内附redis持久化官方传送门在开头)

本文详细介绍了Redis的两种持久化方式:RDB(快照)和AOF(追加日志)。RDB在特定条件或命令触发下创建数据集的快照,适合备份和灾难恢复;AOF记录每次写操作命令,确保数据安全性,支持配置不同的同步策略。AOF重写用于压缩文件大小,避免文件过大。Redis通过混合持久化在AOF重写时同时利用RDB,提供更快的加载速度。在故障恢复时,AOF通常丢失的数据更少。文章还讨论了相关配置指令和问题处理,如AOF文件截断和崩溃的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


官方持久化描述链接

1.rdb

1.1 rdb执行流程

rdb持久化方式一
  • 通过配置参数,配置文件写入
save 60 1000 #60秒内有1000个key发生变化,就会触发一次rdb快照的执行
rdb持久化方式二(and only after it gets synched on disk using the fsync system call)
  • 在客户端执行bgsave命令显示触发一次rdb快照的执行,bgsave执行流程图如下:
    在这里插入图片描述
  • 步骤(中文)

在客户端输入bgsave命令后,Redis调用bgsaveCommand函数,该函数fork一个子进程执行rdbSave函数进行实际的快照存储工作,而父进程可以继续处理客户端请求。当子进程退出后,父进程调用相关回调函数进行后续处理。

  • 步骤(英文)
    Whenever Redis needs to dump the dataset to disk, this is what happens:

1.Redis forks. We now have a child and a parent process.
2.The child starts to write the dataset to a temporary RDB file.
3.When the child is done writing the new RDB file, it replaces the old one.

1.2 rdb文件结构

1.2.1 整体文件结构(rdb文件结构)

在这里插入图片描述
1)头部5字节固定为“REDIS”字符串。
2)4字节的RDB版本号(RDB_VERSION,注意不是Redis的版本号),当前RDB版本号为9,填充为4字节之后为0008。
3)辅助字段(AUX_FIELD_KEY_VALUE_PAIRS,见表20-1)。

在这里插入图片描述

  • 辅助字段可以标明以下信息:
    ❏ 数据库序号:指明数据需要存放到哪个数据库。
    ❏ 当前数据库键值对散列表的大小。Redis的每个数据库是一个散列表,这个字段指明当前数据库散列表的大小。这样在加载时可以直接将散列表扩展到指定大小,提升加载速度。
    ❏ 当前数据库过期时间散列表的大小。Redis的过期时间也是保存为一个散列表,该字段指明当前数据库过期时间散列表的大小。
    ❏ Redis中具体键值对的存储。
    ❏ RDB文件结束标志。
    ❏ 8字节的校验码。

  • 通过上述结构的描述,请思考:加载RDB文件的时候怎么区分加载的是辅助字段还是数据库序号或者是其他类型呢?其实,在RDB每一部分之前都有一个类型字节,在Redis中称为opcodes。如下所示:

1.2.2 键的保存形式
  • Redis中键都是字符串,所以本节介绍的就是RDB中如何保存一个字符串,其实也是一个比较常见的方法,如图20-5所示。

在这里插入图片描述

  • 前边LENGTH字段表示字符串长度,后边STRING即具体的字符串内容。LENGTH为了通用可以使用8个字节保存,但这样很明显会导致空间的浪费。Redis中的LENGTH是个变长字段,通过首字节能够知道LENGTH字段有多长,然后读取LENGTH字段可以知道具体的STRING长度。LENGTH字段类型如下:
1.2.3 值的保存形式
1.2.4 rdb实例

1.3 rdb的优势和缺点

rdb优势

1.RDB 是一个非常紧凑的单文件点,可以及时表示您的 Redis 数据。RDB 文件非常适合备份。例如,您可能需要在最新的 24 小时内每小时存档一次 RDB 文件,并将 RDB 快照保存 30 天。这样,您就可以在发生灾难时轻松恢复不同版本的数据集。
2.RDB 非常适合灾难恢复,它是一个紧凑的文件
3.RDB 最大限度地提高 Redis 性能,因为 Redis是fork子进程来完成持久化的操作
4.与 AOF 相比,RDB 能够在大量数据的情况下更快地重新启动。加载数十G的文件只要几分钟

rdb缺点

1.在服务器宕机的时候,rdb不利于保存更多数据,需要合理设置rdb持久化的配置,owever you’ll usually create an RDB snapshot every five minutes or more, so in case of Redis stopping working without a correct shutdown for any reason you should be prepared to lose the latest minutes of data.
2.rdb需要fork子进程去持久化,但是如果rdb文件太大,可能会导致主线程服务器停止服务几毫秒甚至一秒

2.aof

  • 1.aof定义:

AOF是Redis的另外一种持久化方式。简单来说,AOF就是将Redis服务端执行过的每一条命令都保存到一个文件,这样当Redis重启时只要按顺序回放这些命令就会恢复到原始状态

  • 2.aof和rdb的比较

1)实现方式:RDB保存的是最终的数据,是一个最终状态,而AOF保存的是达到这个最终状态的过程.很明显,如果Redis有大量的修改操作,RDB中一个数据的最终态可能会需要大量的命令才能达到,这会造成AOF文件过大并且加载时速度过慢.
2)加载过程:RDB只需要把相应数据加载到内存并生成相应的数据结构(有些结构如intset、ziplist,保存时直接按字符串保存,所以加载时速度会更快),而AOF文件的加载需要先创建一个伪客户端,然后把命令一条条发送给Redis服务端,服务端再完整执行一遍相应的命令。根据Redis作者做的测试,RDB 10s~20s能加载1GB的文件,AOF的速度是RDB速度的一半(如果做了AOF重写会加快)。
3)加载aof文件 twice per gigabyte in Redis 2.6,2G每秒加载

2.1 aof执行流程(通过写入缓冲区+把缓冲区数据的内容写入一个文件这两个步骤实现aof)

  • 介绍Redis服务端执行命令时如何同步到AOF文件以及AOF文件的格式,然后介绍Redis不同的配置对性能和安全性的影响。
2.1.1 aof命令同步

+通过第6章命令的执行流程,我们看到每一条命令的执行都会调用call函数,AOF命令的同步就是在call命令中实现的,如图20-13所示。
在这里插入图片描述

  • 如果开启了AOF,则每条命令执行完毕后都会同步写入aof_buf中,aof_buf是个全局的SDS类型的缓冲区。那么命令是按什么格式写入缓冲区中的呢?
  • Redis通过catAppendOnlyGenericCommand函数将命令转换为保存在缓冲区中的数据结构,我们通过在该函数处设置断点,打印出转换后的格式。首先使用gdb调试Redis,并在catAppendOnly-GenericCommand函数处设置断点,然后在客户端执行一条命令:
  • 在gdb处执行该函数,然后打印出返回值,如下:
    在这里插入图片描述
  • 即命令“set key aof”保存在缓冲区中的格式为“*3\r\n$3\r\nset\r\n$3\r\nkey\r\n$3\r\naof\r\n”。“\r\n”为分隔符,去掉分隔符之后为如图20-14所示结构。

在这里插入图片描述

2.1.2 aof文件写入(write+fsync:write写文件到内核的缓冲区,fsync把数据从内核缓冲区写到硬盘)
  • AOF持久化最终需要将缓冲区中的内容写入一个文件,写文件通过操作系统提供的write函数执行。但是write之后数据只是保存在kernel的缓冲区中,真正写入磁盘还需要调用fsync函数。fsync是一个阻塞并且缓慢的操作,所以Redis通过appendfsync配置控制执行fsync的频次。
  • 具体有如下3种模式。

❏ no:不执行fsync,由操作系统负责数据的刷盘。数据安全性最低但Redis性能最高。
❏ always:每执行一次写入就会执行一次fsync。数据安全性最高但会导致Redis性能降低。
❏ everysec:每1秒执行一次fsync操作。属于折中方案,在数据安全性和性能之间达到一个平衡。

  • 生产环境一般配置为appendfsync everysec,即每秒执行一次fsync操作。

  • aof文件创建及aof重写步骤大略解析:

1.redis会fork出来一个子进程
2.The child starts writing the new AOF in a temporary file.
3.The parent accumulates all the new changes in an in-memory buffer (but at the same time it writes the new changes in the old append-only file, so if the rewriting fails, we are safe).
4.When the child is done rewriting the file, the parent gets a signal, and appends the in-memory buffer at the end of the file generated by the child.
5.Profit! Now Redis atomically renames the old file into the new one, and starts appending new data into the new file.

2.2 aof重写和aof触发方式

  • aof重写定义:

随着Redis服务的运行,AOF文件会越来越大,并且当Redis服务有大量的修改操作时,对同一个键可能有成百上千条执行命令。AOF重写通过fork出一个子进程来执行,重写不会对原有文件进行任何修改和读取,子进程对所有数据库中所有的键各自生成一条相应的执行命令,最后将重写开始后父进程继续执行的命令进行回放,生成一个新的内容简短的AOF文件:

2.2.1 aof重写触发方式
2.2.1.1 aof重写触发方式一:配置自动触发(Redis 2.4及以后)
  • 配置文件
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
  • 当AOF文件大于64MB时,并且AOF文件当前大小比基准大小增长了100%时会触发一次AOF重写。那么基准大小如何确定呢?
  • 基准大小界定:起始的基准大小为Redis重启并加载完AOF文件之后,aof_buf的大小。当执行完一次AOF重写之后,基准大小相应更新为重写之后AOF文件的大小。
  • 做如上配置之后,Redis服务器会根据配置自动触发AOF重写。
2.2.1.2 aof重写触发方式二:手动执行(Redis 2.4以前)

在这里插入图片描述

  • 下边重点看看手动触发AOF重写,通过在客户端输入bgrewriteaof命令,该命令调用bgrewriteaofCommand,然后创建管道(管道的作用下文介绍), fork进程,子进程调用rewriteAppendOnlyFile执行AOF重写操作,父进程记录一些统计指标后继续进入主循环处理客户端请求。当子进程执行完毕后,父进程调用回调函数做一些后续的处理操作。

  • 我们知道RDB保存的是一个时间点的快照,但是AOF故障时最少可以只丢失一条命令。图20-15中的子进程执行重写时可能会有成千上万条命令继续在父进程中执行,那么如何保证重写完成后的文件也包括这些命令呢?

  • 很明显,首先需要在父进程中将重写过程中执行的命令进行保存,其次需要将这些命令在重写后的文件中进行回放。Redis为了尽量减少主进程的阻塞时间,通过管道按批次将父进程累积的命令发送给子进程,由子进程重写完成后进行回放。因此子进程退出后只会有少量的命令还累积在父进程中,父进程只需回放这些命令即可。

  • 下面介绍重写时父进程用来累积命令使用的结构体。在图20-13中,如果服务端执行一条命令时正在执行AOF重写,命令还会同步到aof_rewrite_buf_blocks中,这是一个list类型的缓冲区,每个节点中保存一个aofrwblock类型的数据,代码如下:
    在这里插入图片描述

  • 该结构体中会保存10MB大小的缓冲区内容,并且有缓冲区使用和空闲长度的记录。当一个节点缓冲区写满之后,会开辟一个新的节点继续保存执行过的命令。

  • 数据通过该结构体保存到父进程中后,那么如何通过管道同步给子进程呢?来看图20-16。
    在这里插入图片描述

  • 父进程在fork之前会建立3对管道:fd0/fd1、fd2/fd3、fd4/fd5,它们各自配对执行。父进程通过fd1将执行aof重写时累积的命令发送给子进程,子进程通过fd0进行接收并保存。当子进程执行完重写之后,向fd3写入一个“!”号通知父进程不需要继续通过管道发送累积命令,父进程通过fd2接收到“!”号之后向fd5也写入一个“! ”号进行确认。子进程通过fd4同步阻塞接收到“! ”号后才可进行后续的退出操作。退出时首先会将接收到的累积命令进行回放,然后执行fsync。

2.2.2 aof和rdb混合持久化方式
  • 定义:

混合持久化指进行AOF重写时子进程将当前时间点的数据快照保存为RDB文件格式,而后将父进程累积命令保存为AOF格式。最终生成的格式如图20-17所示。

在这里插入图片描述

  • 加载时,首先会识别AOF文件是否以REDIS字符串开头,如果是,就按RDB格式加载,加载完RDB后继续按AOF格式加载剩余部分。

在这里插入图片描述

  • 是否开启混合持久化由如下配置设置:
aof-use-rdb-preamble yes
  • 图20-15中,子进程执行rewriteAppendOnlyFile函数时会判断该配置是否开启,如果开启,则首先按RDB的保存方式保存当前数据快照。保存完毕后回放累积命令到文件末尾即可。

2.3 aof持久化优缺点

aof持久化优点

1.可以根据更改配置修改aof落盘的策略,更具有耐用性
2.aof记录的只是操作的指令,就算一些原因使aof操作崩溃,但是使用redis-check-aof工具也能很容易的修复
3.当aof文件太大时,redis会启动aof重写,减少aof的大小,等aof重写完成,redis就会更换两个文件,旧的删除,用新的aof文件用来写aof数据
4.AOF 以易于理解和解析的格式一个接一个地包含所有操作的日志。您甚至可以轻松导出 AOF 文件。例如,即使您意外地使用FLUSHALL命令冲洗了所有内容,只要在此期间没有重写日志,您仍可以通过停止服务器、删除最新命令和重新启动 Redis 来保存数据集。

aof持久化缺点

1.AOF 文件通常大于同一数据集的等效 RDB 文件。
2.Aof 可能比 Rdb 慢, 这取决于确切的 fsync 策略。一般来说,fsync 设置为每秒性能仍然很高,并且随着 fsync 的禁用,即使在高负荷下,它的速度也应该与 RDB 一样快。尽管如此,RDB 还是能够为最大延迟提供更多保证,即使在编写负载巨大的情况下
3.过去,我们在特定命令中遇到罕见的错误(例如,有一个涉及阻止命令(如BRPOPLPUSH),导致产生的 AOF 在重新加载时无法重现完全相同的数据集。这些错误很少见,我们在测试套件中测试自动创建随机复杂的数据集,并重新加载它们以检查一切正常。然而,在 RDB 的持久性下,此类错误几乎是不可能的。为了更清楚地说明这一点:Redis AOF 的工作原理是逐步更新现有状态,就像 MySQL 或 MongoDB 所做的那样,而 RDB 快照会一次又一次地从零开始创建一切,这在概念上更加强大。但是 - 1) 应该指出,每次 AOF 被 Redis 重写时,它都是从数据集中包含的实际数据开始从零开始重新创建的,与始终附加的 AOF 文件(或重写一个重写读旧 AOF 而不是在内存中读取数据)相比,对 bug 的阻力更大。2) 我们从未收到过用户关于在现实世界中检测到的 AOF 崩溃的报告。

3.rdb和aof相关配置指令

4.其他问题

4.1 aof文件被截断了怎么办?

  • 可能原因:

1.写aof文件写到一般,服务器崩溃了
2.写aof文件的时候,空间被写满了

  • 报错信息日志显示
* Reading RDB preamble from AOF file...
* Reading the remaining AOF tail...
# !!! Warning: short read while loading the AOF file !!!
# !!! Truncating the AOF at offset 439 !!!
# AOF loaded anyway because aof-load-truncated is enabled
  • 解决方法:
1.备份aof文件
2.用redis-check-aof工具修复aof文件
redis-check-aof --fix
3.用diff -u检测两个aof文件,一个是损坏,一个是修复后的
4.用修复后的文件重启redis服务器

4.2 aof文件崩溃了怎么办

这时候情况比aof文件被阶段更糟糕,日志报错信息如下

* Reading the remaining AOF tail...
# Bad file format reading the append only file: make a backup of your AOF file, then use ./redis-check-aof --fix <filename>
  • 解决方法:

1.启动redis-check-aof工具,但是一开始用这个工具,先跳到崩溃的那一行,看是否能人工修复这个问题
2.要不就是启动redis-check-aof工具,但是顺坏区域后面的文件将会被全部丢弃

4.3 redis的读写操作:包括aof和rdb文件产生是序列化的、顺序的、sequential的,因为不需要改成随机的

+下面是redis工作人员的原话

Redis persistence demystifiedMonday, 26 March 12

AOF rewrites are generated only using sequential I/O operations, so the whole dump process is efficient even with rotational disks (no random I/O is performed). This is also true for RDB snapshots generation. The complete lack of Random I/O accesses is a rare feature among databases, and is possible mostly because Redis serves read operations from memory, so data on disk does not need to be organized for a random access pattern, but just for a sequential loading on restart.

5.本章小结

### Redis RDB AOF 持久化方式对比 #### 1. 基本概念 Redis 提供了两种主要的持久化机制:RDBRedis DataBase) AOF(Append Only File)。 - **RDB** 是一种快照形式的持久化方法,它会在指定的时间间隔内保存内存中的数据到磁盘上[^2]。 - **AOF** 则通过记录服务器接收到的每一条命令来实现持久化,类似于数据库的日志追加操作[^3]。 --- #### 2. 数据存储格式 - **RDB**: 存储的是某一时刻的数据快照,采用紧凑型二进制格式,因此文件体积更小,适合用于备份或灾难恢复场景[^1]。 - **AOF**: 记录的是每次写入操作的具体指令,以纯文本的形式保存,便于理解修改。 --- #### 3. 对性能的影响 - **RDB**: 创建快照的过程通常由后台子进程完成,不会阻塞主线程处理客户端请求,从而对 Redis 的正常运行影响较小。然而,在高并发环境下频繁触发快照可能会增加 I/O 负载。 - **AOF**: 每次执行写操作都会同步至日志文件,默认情况下可能带来一定的延迟开销。不过可以通过配置 `appendfsync` 参数调整刷盘频率(如 always、everysec 或 no),在安全性性能之间找到平衡点。 --- #### 4. 故障恢复能力 - **RDB**: 如果发生宕机事件,则最后一次成功生成的快照之后新增的数据将会丢失;但由于其结构简单高效,在大规模数据集加载时速度较快。 - **AOF**: 可提供更高的数据安全性保障,即使系统崩溃也能依据完整的命令序列重建原始状态。但是随着日志增长过大会降低启动效率,需定期启用重写功能优化大小。 --- #### 5. 使用场景推荐 | 特性/需求 | 推荐方案 | |------------------|------------------| | 高效备份 | RDB | | 极致数据保护 | AOF | | 快速重启恢复 | RDB | | 易维护可调试性 | AOF | 实际应用中还可以两者结合使用——利用 RDB 实现周期性的冷备存档,同时依靠 AOF 来弥补实时增量部分的安全隐患。 ```python # 启用混合模式示例配置 (redis.conf) save 900 1 # 设置 RDB 自动保存条件之一 appendonly yes # 开启 AOF 功能开关 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值