Redis RDB 与 AOF 持久化策略
一Redis 持久化的好处1.1 减少业务数据的丢失Redis 在运行过程中所有的数据都处于内存之中这也是读写性能高效的原因之一。但也带来一个致命的问题就是数据易丢失。一旦Redis 进程重启或者电脑断电服务器宕机内存里面的数据将全部丢失。并且无法做冷备份和故障回溯Redis提供数据持久化的给业务数据上一层保险以此来减少数据的丢失。一开始 Redis 的持久化不是一开始就完美的它经历了三个重要阶段的演进RDBRedis DataBase 快照时代从 Redis 诞生之初0.08 版本2009年就有了。这是最古老的持久化方式。AOFAppend Only File 追加文件时代到了1.1 版本2010年因为 RDB 可能会丢失最后一次快照后的数据官方引入了 AOF记录每一次写操作。混合持久化时代RDB AOF到了4.0 版本2017年官方发现 AOF 文件太大了恢复太慢于是把 RDB 和 AOF 结合起来诞生了“混合持久化”。redis 默认采用的持久化方案取决于你使用的版本Redis 4.0 之前默认只开启RDB。Redis 4.0 到 6.x默认同时开启 RDB 和 AOFAOF 默认每秒刷盘一次everysecRedis 至今包括 7.x / 8.x默认只开启 RDB 持久化AOF 默认关闭混合持久化开关虽然默认 yes但只有在 AOF 开启时才会生效。1.2 向数据库能力扩展如果 Redis 没有良好的持久化支撑那么 Redis 的功能定位只能停留在Cache缓存临时存储。但是有了持久化 Redis 可以承担轻量数据库状态存储分布式协调数据锁队列。这也是为什么会有很多系统会用 Redis 替换部分数据库场景1.3 满足不同场景的数据安全需求不同业务对数据丢失的容忍度不同持久化两种策略让用户权衡特性RDB快照AOF追加日志工作原理某个时间点生成全量数据快照记录每个写操作命令类似日志丢失风险可能丢失上次快照后的数据如每5分钟一次最多丢失1秒或1条命令根据配置文件大小较小压缩后的二进制文件较大但支持 rewrite 重写压缩恢复速度快直接加载慢需重放所有命令缓存场景可容忍少量数据丢失 → 只用 RDB 或不持久化追求高性能。支付/计数场景要求几乎零丢失 → 配合 AOFappendfsync always或 AOFRDB 混合模式二RDB 持久化RDB 是 Redis快照持久化在指定时间节点将内存中全量数据以二进制压缩文件默认dump.rdb落地磁盘。 在学习 RDB 持久化之前首先我们要知道当前 redis 采用的是那种持久化方案。判断依据是什么如果不是 RDB 我们需求给切换到 RDB 的持久化方案进行学习与讲解2.1 查看当前 redis 持久化方案【判断 RDB 是否开启】CONFIG GET save # 返回 空字符串RDB 自动持久化关闭 # 返回类似 900 1、300 10、60 10000 等配置RDB 自动持久化开启【判断 AOF 是否开启】CONFIG GET appendonly # 返回 appendonly noAOF 关闭Redis 默认状态 # 返回 appendonly yesAOF 开启【混合判断结论】在了解混合判断之前我们需要理解混合的工作原理不然对于是否开启了混合持久化会有所误解。首先需要了解的是 Redis 的混合持久化并不是独立的持久化方案而是 AOF 的一种优化机制。它通过在 AOF 重写时将 RDB 快照作为文件开头再追加增量写命令从而兼顾了 RDB 的快速恢复能力和 AOF 的数据完整性。需要注意的是只有在开启 AOFappendonlyyes时该机制才会生效否则即使配置存在也不会参与实际运行。config get aof-use-rdb-preamble # 返回 aof-use-rdb-preamble no : 配置关闭 # 返回 aof-use-rdb-preamble yes : 配置开启 # 需要注意的是只有在开启 AOFappendonlyyes时该机制才会生效 # 否则即使配置存在(aof-use-rdb-preamble yes)也不会参与实际运行。所以具体判断如下默认出厂状态save有规则 appendonly no→只启用 RDBAOF 关闭Redis 原生默认两者都开启save有规则 appendonly yes→RDB AOF 双持久化生产常用只开 AOFsave appendonly yes→仅 AOF全关闭save appendonly no→无任何持久化纯缓存宕机丢数据小编环境下的 Redis 整体判断命令如下127.0.0.1:6379 config get save # 查看 RDB 的规则 1) save 2) 3600 1 300 100 60 10000 127.0.0.1:6379 config get dbfilename # 查看 RDB 持久化文件名称 1) dbfilename 2) dump.rdb 127.0.0.1:6379 config get dir # 查看 RDB 持久化路径 1) dir 2) /usr/local/redis 127.0.0.1:6379 config get appendonly # 查看 AOF 持久化开关 1) appendonly 2) no 127.0.0.1:6379 config get aof-use-rdb-preamble # 查看 aof-use-rdb-preamble 配置开关 1) aof-use-rdb-preamble 2) yes【结论】很明显是save有规则 appendonly no→只启用 RDBAOF 关闭Redis 原生默认也就是持久化只采用了 RDB 的方案。【提问】假如 aof-use-rdb-preamble 返回 no 配置关闭那会不会影响到redis的持久化【回答】答案是不会的。原因是混合持久化 (aof-use-rdb-preamble) 是 AOF 的一个优化机制。并不是一个独立的持久化功能。所以既然是 AOF 的一个优化机制那么aof-use-rdb-preamble 返回 no 作用也仅仅只是关闭 AOF 的优化机制但是这并不影响 AOF 正常持久化。【提问】假如 AOF 持久化都关闭了采用的是 RDB 持久化那么 aof-use-rdb-preamble 配置无论是开启(yes)还是关闭(no)会不会对 Redis 持久化有影响为什么【回答】答案是不会有影响因为 AOF 持久化都关闭了那么 aof-use-rdb-preamble 配置无论是开启(yes)还是关闭(no)都不会对 Redis 持久化有影响。因为混合持久化仅仅只是 AOF 的一个优化机制。现在是 AOF 整个功能都关闭了那 AOF 的优化机制配置都没有使用的地方所以配置是开还是关都没有影响。如果RDB, AOF 全部都关闭那就是表上第四种redis 没有持久化仅仅当作 Cache 使用。2.2 RDB 的配置参数在使用 RDB 之前我们先将 RDB 的配置参数给讲明白参数如下配置项作用默认值stop-writes-on-bgsave-error磁盘故障写保护yesrdbcompression压缩 RDByesrdbchecksum校验和yesdbfilename文件名dump.rdbdir工作目录./编译时指定save自动触发条件3600 1 300 100 60 10000Redis 为 RDB 持久化“保驾护航”的一整套控制开关。这些参数本质上在解决 3 类问题类别解决什么问题 文件管理存哪叫什么 比如dbfilename, dir 数据安全写失败怎么办文件坏了怎么办比如磁盘故障写保护⚙ 性能优化CPU / IO 怎么平衡比如是否要开启备份文件的压缩备份文件完整性校验等等详细的参数讲解如下dbfilename -- 文件名作用定义 RDB 文件名dbfilename dump.rdb # 位置在redis.conf 配置文件本质 RDB 持久化输出文件的名字运行时行为当触发 BGSAVEdir dbfilename → 最终路径例如dir /usr/local/redis dbfilename dump.rdb 最终文件 /usr/local/redis/dump.rdb生产建议可以改备份文件名称redis-prod-dump.rdb 。好处就是多实例数据备份更清晰容易区分❗风险点 不影响性能 但命名混乱会导致备份混乱dir ./ -- 存储目录作用定义 RDB / AOF 存储目录dir /usr/local/redis本质所有持久化文件的“根目录”包括 dump.rdb appendonly.aof运行时行为Redis 所有持久化文件都写在 dir 目录下生产强烈建议必须使用绝对路径 ❗例如dir /data/redis 。以及单独挂盘SSD不要和系统盘混用❗风险点如果 dir 指定目录无权限磁盘满会导致RDB 失败 → 触发stop-writes-on-bgsave-errorstop-writes-on-bgsave-error yes -- 磁盘故障写保护作用RDB 失败时是否停止写入stop-writes-on-bgsave-error yes本质“自我保护机制”运行时行为当发生磁盘满权限问题 IO错误导致 BGSAVE 失败。配置是 yes 拒绝所有写操作no 则表示继续写但不会落盘配置结果yes❌ 拒绝所有写操作no✅ 继续写但不会落盘举个真实事故场景磁盘满了 ↓ RDB 一直失败 ↓ 如果 stop-writes no ↓ Redis 继续写用户数据正常 ↓ 但全部没持久化 ❗ ↓ 一旦重启 → 数据全没 这就是灾难级问题推荐配置必须 yes默认就是rdbcompression yes --压缩 RDB 文件作用是否压缩 RDB 文件rdbcompression yes 本质用 LZF 算法压缩 RDB运行时行为开启关闭文件更小文件更大CPU 有开销CPU 更省场景选择 推荐开启默认 磁盘敏感数据量大 可以关闭 CPU 很紧张极致性能场景实际影响压缩率约 30%~60% CPU 开销可接受rdbchecksum yes --RDB 文件完整性校验作用RDB 文件完整性校验rdbchecksum yes本质在 RDB 文件末尾加 CRC 校验值什么时候用Redis 启动加载 RDB 时会校验文件是否损坏运行时行为开启关闭更安全更快多 ~10% CPU无校验场景建议 强烈建议开启默认生产环境数据重要 可关闭极致性能测试环境风险点关闭后RDB 损坏 → Redis 可能加载异常数据 ❗repl-diskless-sync -- 是否无盘同步作用主从复制时是否“无盘同步”repl-diskless-sync yes背景Redis 主从同步流程主节点生成 RDB ↓ 发给从节点两种模式传统模式默认主节点 生成 RDB 文件 → 写磁盘 → 再发送 # 缺点多一次磁盘 IO -- 慢无盘模式diskless主节点 直接通过 socket 发送 RDB 不落盘对比模式特点有盘稳定无盘更快、低 IO 使用建议 推荐开启大规模集群repl-diskless-sync yes 不建议 小规模部署,或者网络不稳定不建议开启更改 RDB 相关参数当了解完参数的作用之后我们就可以根据自己的服务环境来决定哪些配置参数开启。比如小编这边想将数据备份文件改为toast-redis-dump.rdb数据备份存储路径改为/usr/local/redis/data# 所以完整的备份文件路径如下 /usr/local/redis/data/toast-redis-dump.rdb然后我还想开启数据备份失败写保护策略这样 RDB 备份失败之后将禁止写入操作。然后至于备份文件的压缩节省空间以及备份文件完整性的校验都采用默认状态至于生产的备份数据要不要落盘在发送还是不落盘直接发送(无盘同步)。采用默认 直接落盘再同步。所有配置参数完整内容如下dbfilename toast-redis-dump.rdb # RDB 备份文件名称 dir /usr/local/redis/data # 存储目录 stop-writes-on-bgsave-error yes # RDB 备份失败是否禁止写操作默认开启禁止 rdbcompression yes # RDB 备份文件压缩是否开启默认开启压缩 rdbchecksum yes # RDB 备份文件完整性校验是否开启默认开启然后杀死 redis.conf。重新启动一下redis,[roottoast-server redis]# pkill redis-server [roottoast-server redis]# bin/redis-server conf/redis.conf2.3 触发 RDB 持久化2.3.1 save 规则触发 RDB 持久化现在是所有的准备工作都完毕。现在正式开讲 RDB 业务流程。以及 RDB 持久化触发的机制。首先我们得先了解 save 的配置规则# 以下是一个通用生产配置示例(配置在redis.conf) 中 save 3600 1 # 1小时内至少1次写入 → 备份 save 300 100 # 5分钟内至少100次写入 → 备份 save 60 10000 # 1分钟内至少10000次写入 → 备份 # save 规则解释 # 1. save 秒 写次数 这是一条规则。表示 在多少秒内至少发生了多少次写操作则触发 RDB 持久化 # 2. 一次性可以设置多条规则多条规则之间的连接关系是 OR/或 关系。 只要触发了其中一条规则 # 就会发生 RDB 持久化。 # 3. 多条规则之间不会重复触发。因为在任何一次检查周期每 1 秒中 # 一旦满足了某一条规则并触发了 BGSAVERedis 就会立即停止本轮检查 # 不会再去判断剩下的规则是否也满足查看我当前 Redis 的 save 规则有哪些打开 redis.conf。我的redis.conf 默认是没有写 save 的规则的。redis 在启动的时候会默认填充 save 规则可以通过 redis-cli 进行查询127.0.0.1:6379 config get save 1) save 2) 3600 1 300 100 60 10000 # 这里的配置就是 save 3600 1 # 1小时内至少1次写入 → 备份 save 300 100 # 5分钟内至少100次写入 → 备份 save 60 10000 # 1分钟内至少10000次写入 → 备份这边为了学习和测试 RDB 小编进行 save 的临时更改# save 15 1 15秒内至少1次写入 → 备份 # save 30 3 30秒内至少3次写入 → 备份 # save 60 5 60秒内至少5次写入 → 备份 # 对应的命令如下# 将 RDB 自动触发规则修改为短期测试规则 # CONFIG SET save 15 1 30 3 60 5 # 已设置 127.0.0.1:6379 CONFIG SET save 15 1 30 3 60 5 OK 127.0.0.1:6379 config get save 1) save 2) 15 1 30 3 60 5这边进行测试# 写操作执行前 无RDB备份文件 [roottoast-server redis]# ll /usr/local/redis/data/ total 0 # 执行写操作 [roottoast-server redis]# bin/redis-cli 127.0.0.1:6379 auth ToastR#16 OK 127.0.0.1:6379 set testkey valuetest OK 127.0.0.1:6379 set testkey2 valuetest2 OK # 过了10 秒 满足 save 10 1 规则 10秒内至少1次写入 → 备份 # 可以看到数据已备份 [roottoast-server ~]# ll /usr/local/redis/data/ total 4 -rw-r--r-- 1 root root 133 Jun 16 18:44 toast-redis-dump.rdb查看对应的日志[roottoast-server redis]# tail -f logs/redis_6379.log # 15秒内出现了1次数据变化所以触发 RDB 1 changes in 15 seconds. Saving... # 启用 BGSAVE 命令并且为其分配系统进程ID Background saving started by pid 3341938 # 数据存储到磁盘 BGSAVE done, 5 keys saved, 0 keys skipped, 200 bytes written. DB saved on disk # 子进程的数据处理 Fork CoW for RDB: current 0 MB, peak 0 MB, average 0 MB # 子进程写入完成 Background saving terminated with success2.3.2 主动触发 RDB 持久化这边我们可以看到通过 save 规则来触发 RDB 持久化机制。现在我们将 save 规则恢复默认127.0.0.1:6379 config set save 3600 1 300 100 60 10000 OK 127.0.0.1:6379 config get save 1) save 2) 3600 1 300 100 60 10000 # 这里的配置就是 save 3600 1 # 1小时内至少1次写入 → 备份 save 300 100 # 5分钟内至少100次写入 → 备份 save 60 10000 # 1分钟内至少10000次写入 → 备份之所以恢复我为了讲解另一种情况就是由于 RDB 是需要触发 save 规则条件才会执行 RDB 持久化。那这种触发是属于被动触发。只有达到条件才可以执行RDB持久化。缺少主动的执行RDB持久化。比如在五分钟内我执行了90条写操作但是还并没有达到 save 规则来触发RDB持久化进行备份。5分钟内300秒执行了90次写操作——这不符合300 100规则因为90 100也不符合3600 1规则因为时间还没到3600秒也不符合60 10000规则。因此不会触发被动保存。此时Redis确实不会自动执行备份。如果此时Redis突然宕机这90次写入就会丢失。所以这个时候可以采用主动执行 RDB 持久化的方式进行。针对这种情况Redis提供了两种主动执行RDB持久化的方式。下面我们来详细拆解SAVE 命令 同步阻塞 - 严禁在生产环境使用127.0.0.1:6379 SAVERedis 服务器会阻塞所有客户端的请求在主线程中直接创建 RDB 文件。在文件生成完毕之前Redis 无法处理任何读写操作。业务场景如果数据量太大RDB期间你的业务程序会报连接超时。仅建议在内存非常小、数据量极少或者维护关机时使用绝对不要在运行中的生产环境执行【测试执行】[roottoast-server redis]# rm data/* # 先删除之前的 RDB 备份文件 rm: remove regular file data/toast-redis-dump.rdb? y [roottoast-server redis]# ll data/ # 现在没有数据 # redis-cli 端 127.0.0.1:6379 set save:key save:value OK 127.0.0.1:6379 set save:key1 save:value1 OK 127.0.0.1:6379 SAVE OK [roottoast-server redis]# ll data/ total 4 -rw-r--r-- 1 root root 177 Jun 17 10:31 toast-redis-dump.rdbBGSAVE 命令异步后台执行 - 生产环境标准方案127.0.0.1:6379 BGSAVERedis 会调用fork()系统调用创建一个子进程由子进程在后台异步生成 RDB 文件。父进程主线程继续处理客户端的读写请求完全不影响业务。业务场景当你发现 5 分钟内执行了 90 次写入担心数据安全时直接在客户端执行BGSAVERedis 会立即开始备份当前内存中的全量数据。127.0.0.1:6379 BGSAVE Background saving started 127.0.0.1:6379验证执行后可以用127.0.0.1:6379 LASTSAVE命令查看最后一次成功备份的时间戳确认是否执行完毕。127.0.0.1:6379 LASTSAVE # 2026-06-17 约 02:46 UTC / 北京时间 10:46 (integer) 1781664387 127.0.0.1:6379三AOF 持久化3.1 AOF 简介RDB 持久化可生成完整的数据集备份但该持久化模式存在性能损耗问题每次触发持久化流程时Redis 会派生全新子进程依托子进程完成数据持久化写入。频繁派生子进程将产生较高的系统资源开销对业务性能影响显著。针对这一短板Redis 内置了 AOF 持久化机制作为轻量化补充方案该机制的核心特性为增量记录所有写数据操作指令。如上图所示每执行一次写操作AOF 都会将操作命令记录到 AOF 的备份文件里面。然后Redis 重启的时候读取数据。3.2 AOF 命令压缩AOF 持久化会逐条记录全部数据操作指令数据恢复时只需重放文件内存储的命令即可完成数据集还原。该模式采用增量追加写入逻辑无需像 RDB 持久化那样 fork 子进程执行落盘操作理论上能够实现极致完整的数据留存但 AOF 机制仍存在两处核心缺陷【文件体积膨胀问题】高并发场景下 AOF 文件会快速增大。例如每秒承载 30 万并发请求时每条业务操作指令均会追加写入文件海量指令会直接造成 AOF 文件体量急剧膨胀。【启动恢复耗时过长】AOF 文件持续膨胀后Redis 重启加载数据阶段需要逐条解析、执行文件内全部历史命令大幅拉长服务启动耗时严重影响业务恢复效率。效果如下图为解决 AOF 文件持续膨胀的问题Redis 引入 AOF 重写机制实现指令压缩。举个例子若多个客户端连续执行多条LPUSH写入指令重写流程会将多条同类合并逻辑压缩为单条等效指令最终仅在新 AOF 文件内留存一条命令以此缩减文件占用空间。模拟命令重写压缩LPUSH toast-queue a LPUSH toast-queue b LPUSH toast-queue c LPUSH toast-queue d LPUSH toast-queue e LPUSH toast-queue f .... # 重写压缩成一条 LPUSH toast-queue a b c d e f ...3.3 AOF 重写也要依托子进程执行为何不直接使用 RDB 持久化尽管 AOF 重写可有效压缩文件体积但该重写逻辑同样交由子进程执行重写期间主进程可持续正常对外提供读写服务若仅依靠子进程生成压缩后的 AOF 文件新产生的业务数据会存在丢失风险。由此容易产生疑问既然 AOF 重写也要依托子进程执行为何不直接使用 RDB 持久化面试题RDB 与 AOF 持久化均通过子进程执行重写 / 快照阶段主进程仍持续接收数据变更二者理论上都存在数据快照不全的情况Redis 为何仍保留 AOF 持久化方案【答案】核心原因是 AOF 的数据完备性远优于 RDBAOF 机制专门设计了配套缓冲区机制用于同步持久化重写期间主进程新增的数据变更而 RDB 快照流程无对应补偿方案。开启 AOF 重写时Redis 会维护两块独立缓冲区一是主进程持有的 AOF 缓冲区二是专属子进程的 AOF 重写缓冲区。重写期间客户端新下发的所有操作指令会同步写入这两块缓冲区(1) 主进程持续向原有 AOF 文件逐条追加完整原始指令保障数据实时落地(2) 子进程依托重写缓冲区执行指令合并压缩生成体积更小的全新 AOF 文件。待子进程完成重写、生成压缩后的完整 AOF 文件后Redis 会原子替换旧的 AOF 文件。整套机制兼顾两大优势一方面通过指令压缩控制文件体积另一方面依靠双缓冲区同步记录新增指令保证数据不丢失。即便重写过程中子进程发生异常崩溃主进程持续写入的原始 AOF 文件依旧完整可独立完成全量数据恢复。3.4 Redis 7.x 系版本以上 AOF 的新特性在 Redis-6.x 系版本里面AOF 就只有那么一个文件会存在数据目录之中但是在 Redis 7.x 系列版本开始采用了多 AOF 文件的存储设计。Redis 7.0 引入的Multipart AOF (MP-AOF) 机制将单个 AOF 文件拆分为一组文件其核心设计目的是为了解决旧版 AOF 重写AOFRW机制存在的内存和磁盘开销问题。旧版 AOF 重写AOFRW的痛点在解释新设计前先回顾旧版的问题重写时主进程会 fork 一个子进程来生成新的 AOF 文件。为了保证数据完整性主进程需要将重写期间的增量写命令同时记录到两个缓冲区aof_buf常规 AOF 缓冲区用于写入旧的 AOF 文件。aof_rewrite_buf专门为重写子进程准备的缓冲区“双写”模式在高写入场景下会带来两大问题内存开销巨大aof_rewrite_buf和aof_buf的内容高度重复可能导致内存占用翻倍。额外的磁盘 I/O 与 CPU 开销重写后期主进程需通过管道将aof_rewrite_buf的数据发给子进程增加了额外的系统开销。重写完成后还需将残留数据再次写入临时文件。Redis 7.0 MP-AOF 的新设计MP-AOF 的核心思路是将对单个文件的复杂操作转变为对多个文件的清晰管理从根本上解决上述问题。1. 三种文件与清单文件MP-AOF 将数据拆分到同一个目录下的三类文件BASE 文件基础 AOF 文件存储某一时刻的完整数据快照经过压缩重写最多只有一个。INCR 文件增量 AOF 文件存储 BASE 文件之后产生的所有增量写命令可以有多个。HISTORY 文件历史文件每次重写成功后旧的 BASE 和 INCR 文件会被标记为 HISTORY 并自动删除。Manifest 清单文件一个清单文件appendfilename.manifest用于记录当前生效的 BASE 和 INCR 文件列表是 Redis 启动时加载数据的“目录”。2. 新机制如何工作重写过程被简化为“创建新文件”和“更新清单”两步不再需要复杂的数据拷贝子进程直接基于当前内存数据创建一个新的 BASE 文件。重写期间主进程的写命令照常追加到当前的 INCR 文件中。新 BASE 文件生成后主进程更新 Manifest 文件将新 BASE 文件和重写期间产生的 INCR 文件标记为最新。旧的 BASE 和 INCR 文件被标记为 HISTORY 并随后删除。新设计带来的核心优势显著降低内存使用彻底消除了aof_rewrite_buf。主进程只需正常写入当前的 INCR 文件子进程直接读取内存数据生成 BASE 文件无需额外的缓冲区和数据传输。减少磁盘 I/O 和 CPU 消耗消除了主、子进程间的数据拷贝和额外的写入操作逻辑更简单、高效。提升数据恢复速度启动时Redis 只需按顺序加载一个 BASE 文件RDB 格式加载快和最新的 INCR 文件命令少回放快比加载单个巨大的 AOF 文件更快。为高级特性奠定基础这种文件组织方式为实现按时间点恢复PITR等高级特性提供了可能。总而言之Redis 7.0 的 MP-AOF 机制通过“化整为零”的文件管理和清晰的“基线增量”思路优雅地解决了旧版 AOF 重写的资源消耗问题是 AOF 持久化机制的一次重要演进3.5 AOF 实操在操作之前先开启 AOF 持久化配置然后重启 Redis 服务。[roottoast-server redis]# vim conf/redis.conf # appendonly no 改为 appendonly yes # wq! 保存并退出 # 重启redis服务 [roottoast-server redis]# pkill redis-server [roottoast-server redis]# bin/redis-server conf/redis.conf # 查看 redis 的存储目录小编设置的是存储目录/usr/local/redis/data [roottoast-server data]# pwd /usr/local/redis/data [roottoast-server data]# ll total 4 drwxr-xr-x 2 root root 4096 Jun 17 16:36 appendonlydir # 所有的 AOF 相关文件都存储在 appendonlydir 目录中 [roottoast-server data]# tree appendonlydir/ appendonlydir/ ├── appendonly.aof.1.base.rdb ├── appendonly.aof.1.incr.aof └── appendonly.aof.manifest现在已经开启了 AOF 持久化处理。顺便查看一下 redis 的启动日志[roottoast-server redis]# tail -f logs/redis_6379.log oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo # redis 版本信息 Redis version8.8.0, bits64, commit00000000, modified0, pid3392721, just started Configuration loaded monotonic clock: POSIX clock_gettime Running modestandalone, port6379. Server initialized BGSAVE done, 0 keys saved, 0 keys skipped, 88 bytes written. # 这里创建了 base file 和 incr file Creating AOF base file appendonly.aof.1.base.rdb on server start Creating AOF incr file appendonly.aof.1.incr.aof on server start Ready to accept connections tcp写入一些数据操作然后观察 AOF 的持久化127.0.0.1:6379 LPUSH stack left-A (integer) 1 127.0.0.1:6379 LPUSH stack left-B (integer) 2 127.0.0.1:6379 LPUSH stack left-C (integer) 3 127.0.0.1:6379 LPUSH stack left-D left-E left-F left-J (integer) 7观察 appendonlydir 目录信息查看 appendonly.aof.1.base.rdb 文件内存[roottoast-server data]# vim appendonlydir/appendonly.aof.1.base.rdb REDIS0014ú redis-ver^E8.8.0ú redis-bitsÀú^EctimeÂ94\2jú^Hused-memÂÀ6^K^ú^Haof-baseÀ^Aÿ^EÚË9dv^A^B打开看到一堆乱码、开头REDIS0014这是标准 RDB 二进制快照文件不是文本不能用 vim 正常阅读。生成时机上一次 AOF 重写BGREWRITEAOF时子进程把当时 Redis 里全部存量数据一次性导出成 RDB 快照作用作为数据恢复的基准底本加载速度远快于纯命令日志乱码原因二进制存储包含版本、内存占用、创建时间、所有 key-value 数据vim 打开只会显示不可读字符不要直接编辑。查看 appendonly.aof.1.incr.aof 文件内容[roottoast-server data]# vim appendonlydir/appendonly.aof.1.incr.aof *2 $6 SELECT $1 0 *3 $5 LPUSH $5 stack $6 left-A *3 $5 LPUSH $5 stack $6 left-B *3 $5 LPUSH $5 stack $6 left-C *6 $5 LPUSH $5 stack $6 left-D $6 left-E $6 left-F $6 left-J里面是可读的 Redis 原始 AOF 协议文本记录重写完成之后新增的所有写命令你只操作了两三条写入这里只会追加你执行过的指令解析这段协议 *2本条命令一共 2 个参数 $6第一个参数长度 6 → SELECT $1第二个参数长度 1 → 0 对应命令SELECT 0切换到 0 号库客户端连接默认会执行这条不算业务写操作 *3本条命令一共 3 个参数 $5LPUSH $5key stack 对应你的写入操作LPUSH stack xxxRedis 重启恢复流程 先加载base.rdb拿到完整存量数据再按顺序逐条执行incr.aof里的新增命令最终还原全部数据。查看 appendonly.aof.manifest 文件内容[roottoast-server data]# vim appendonlydir/appendonly.aof.manifest file appendonly.aof.1.base.rdb seq 1 type b file appendonly.aof.1.incr.aof seq 1 type i startoffset 0该文件是元数据记录着appendonly.aof.1.incr.aof 和 appendonly.aof.1.base.rdb。因为随着数据量的增大这些文件也可以增多。增多的文件都会记录在这个文件里面。什么时候会生成新的 base、新 incr当满足 AOF 重写触发条件文件增长比例 / 手动执行 BGREWRITEAOF会 新建一份新的 base 快照 新建一个全新编号的 incr 增量文件 旧的 base、旧 incr 标记为 history 历史文件后台异步删除。手动触发 AOF -- BGREWRITEAOF127.0.0.1:6379 BGREWRITEAOF Background append only file rewriting started查看 redis 服务日志# 3392721:MM 代表 Master 主进程 进程 PID33927213412211:CC 代表 Child 子进程# 触发 AOF 后台重写的瞬间主进程立刻新建全新增量文件 appendonly.aof.2.incr.aof 3392721:M 17 Jun 2026 17:04:40.055 * Creating AOF incr file appendonly.aof.2.incr.aof on background rewrite # 主进程 fork 出子进程子进程 PID3412211正式启动 AOF 后台重写任务 # fork 操作采用 Copy-On-Write 写时复制不阻塞主进程对外读写 3392721:M 17 Jun 2026 17:04:40.055 * Background append only file rewriting started by pid 3412211 # 子进程执行 BGSAVE将 fork 瞬间内存中所有全量数据导出为 RDB 快照 # 当前数据库仅 1 条有效 key无过期 / 跳过键快照文件总大小 146 字节 3412211:C 17 Jun 2026 17:04:40.057 * BGSAVE done, 1 keys saved, 0 keys skipped, 146 bytes written. # 子进程把生成的 RDB 快照写入临时 BASE 文件文件名携带子进程 PID 做隔离防止多轮重写文件冲突 # 临时文件不会对外生效旧数据文件依然完好重写中途崩溃不会损坏原有持久化文件 3412211:C 17 Jun 2026 17:04:40.059 * Successfully created the temporary AOF base file temp-rewriteaof-bg-3412211.aof 3412211:C 17 Jun 2026 17:04:40.060 * Fork CoW for AOF rewrite: current 0 MB, peak 0 MB, average 0 MB 3392721:M 17 Jun 2026 17:04:40.085 * Background AOF rewrite terminated with success 3392721:M 17 Jun 2026 17:04:40.085 * Successfully renamed the temporary AOF base file temp-rewriteaof-bg-3412211.aof into appendonly.aof.2.base.rdb # 上一轮生效的旧基准文件 .1.base.rdb、旧增量文件 .1.incr.aof 全部标记为 HISTORY 历史文件 3392721:M 17 Jun 2026 17:04:40.089 * Removing the history file appendonly.aof.1.incr.aof in the background 3392721:M 17 Jun 2026 17:04:40.089 * Removing the history file appendonly.aof.1.base.rdb in the background 3392721:M 17 Jun 2026 17:04:40.093 * Background AOF rewrite finished successfully查看 appendonlydir 目录确实已经有新版本的文件[roottoast-server redis]# ll data/appendonlydir/ total 8 -rw-r--r-- 1 root root 146 Jun 17 17:04 appendonly.aof.2.base.rdb -rw-r--r-- 1 root root 0 Jun 17 17:04 appendonly.aof.2.incr.aof -rw-r--r-- 1 root root 102 Jun 17 17:04 appendonly.aof.manifest3.6 混合持久化讲解在 Redis 4.0 的时候引入了 混合持久化是通过 RDB AOF 两种方式实现持久化存储。现在这个多文件 MP-AOF 好像也是 RDB AOF因为从 appendonlydir 目录当中 base.rdb 是一个 RDB 全量生成的二进制备份文件而 incr.aof 是一个 AOF 增量命令写入的文件。那他们之间的区别是什么Redis 4.0 引入了混合持久化aof-use-rdb-preamble yes其中 AOF 重写会生成一个以 RDB 格式开头、后跟增量 AOF 数据的文件。Redis 7.0 的MP-AOF多文件 AOF在逻辑上采用了“RDB AOF”的混合思路但在物理存储上和传统的“RDB AOF”是两码事。1. 传统意义上的“RDB AOF”Redis 4.0~6.x在旧版本中如果你同时开启了 RDB 和 AOF它们是两个独立的文件dump.rdb二进制快照 appendonly.aof命令日志此时所谓的“混合”指的是aof-use-rdb-preambleAOF 前置 RDB 头功能。即AOF 重写时新生成的appendonly.aof文件前半部分是 RDB 二进制数据后半部分是增量 AOF 命令。但物理上它们合并在同一个文件里。2. Redis 7.0 MP-AOF 的“RDB AOF”逻辑混合在 Redis 7.x 的多文件设计中BASE 文件和INCR 文件的关系本质上就是 RDB 和 AOF 的关系【BASE 文件基础文件】实际上就是 RDB 格式如果开启了aof-use-rdb-preamble yes。它存储的是重写那一刻的全量内存快照二进制压缩格式加载极快。【INCR 文件增量文件】是纯 AOF 格式。它存储的是 BASE 文件生成之后新产生的所有增量写命令文本协议格式。所以从逻辑上看Redis 7.0 加载数据时 加载 BASE即 RDB 快照 重放 INCR即 AOF 增量日志。这不就是典型的“混合持久化”吗3. 它们最核心的区别物理 vs 逻辑既然逻辑上都是“RDB AOF”为什么 Redis 7.0 要大费周章拆成多个文件对比维度旧版混合4.0~6.xRedis 7.0 MP-AOF物理文件单文件一个.aof文件里嵌着 RDB 头和 AOF 尾多文件独立的BASE.rdb/BASE.aofINCR.aof重写机制子进程生成新.aof临时文件完成后原子替换旧文件期间有数据拷贝子进程生成新BASE文件主进程追加新 INCR 文件最后更新清单文件Manifest增量数据存储重写期间新增数据先写aof_rewrite_buf最后塞进新文件的尾部重写期间新增数据直接写入新的 INCR 文件无需拷贝给子进程内存开销高需要额外的重写缓冲区双倍内存低无需重写缓冲区主进程写 INCR子进程写 BASE一句话总结你的问题Redis 7.0 的多 AOF 文件设计本质上是把原来“挤在一个文件里的 RDB 和 AOF 数据”拆成了“独立存放的 BASE 文件和 INCR 文件”。它在数据恢复策略上依然是 RDB快速加载全量 AOF回放增量但在文件管理和重写算法上进行了彻底重构解决了旧版单文件重写时的内存瓶颈和额外 I/O 开销。所以你可以这样回答面试官“Redis 7.0 的 MP-AOF 保留了 RDB 快照作为 BASE 文件来加速恢复同时用独立的 INCR 文件记录增量是在混合持久化思想上的物理存储升级而非推翻重来。”