Redis 持久化机制:RDB、AOF 与混合持久化 Redis 持久化机制RDB、AOF 与混合持久化面试热度⭐⭐⭐⭐⭐前置知识Redis 基本数据结构、Linux 进程 fork 概念 目录点击跳转1. 为什么 Redis 需要持久化2. RDB 持久化2.1 基本原理2.2 RDB 的触发方式2.3 RDB 文件结构2.4 配置与实战2.5 RDB 优缺点3. AOF 持久化3.1 基本原理3.2 AOF 的三种写回策略3.3 AOF 重写机制3.4 配置与实战3.5 AOF 优缺点4. RDB vs AOF 全面对比5. Redis 4.0 混合持久化6. 数据恢复流程与优先级7. 面试高频问答推荐阅读1. 为什么 Redis 需要持久化Redis 是一个内存数据库——所有数据都存在内存里。一旦进程退出、服务器重启或宕机内存数据就全丢了。┌─────────────────────────────────────┐ │ Redis 实例运行中 │ │ │ │ 内存: key1value1 key2value2 │ ← 所有读写都在内存 │ key3value3 key4value4 │ │ │ ├─────────────────────────────────────┤ │ ❌ 宕机 / 重启 / kill │ ├─────────────────────────────────────┤ │ │ │ 内存: 空空如也... │ ← 数据全没了 │ │ └─────────────────────────────────────┘持久化就是把内存里的数据定期写到磁盘上重启时再从磁盘加载回内存。┌──────────────┐ ┌──────────────┐ │ Redis 内存 │ ──持久化──→ │ 磁盘文件 │ │ key-value │ ←──恢复─── │ dump.rdb │ │ │ │ appendonly. │ │ │ │ aof │ └──────────────┘ └──────────────┘Redis 提供两种持久化方案方案机制文件格式数据完整性RDB(Redis Database)定时全量快照二进制压缩可能丢最后一次快照后的数据AOF(Append Only File)追加写操作日志文本协议最多丢 1 秒数据2. RDB 持久化2.1 基本原理RDB 的核心思想拍一张内存数据的快照存到磁盘。┌──────────────────────────────────────────┐ │ RDB 生成流程SAVE/BGSAVE │ │ │ │ ┌──────────┐ │ │ │ Redis │ SAVE命令 │ │ │ 主进程 │ ───────→ 同步生成 RDB │ │ └──────────┘ 阻塞所有客户端 │ │ │ │ ┌──────────┐ BGSAVE命令 │ │ │ Redis │ ───────→ fork 子进程 │ │ │ 主进程 │ 继续处理请求 │ │ └────┬─────┘ │ │ │ fork() │ │ ↓ │ │ ┌──────────┐ │ │ │ 子进程 │ ───────→ 写入临时 RDB 文件 │ │ │ (基于 │ 完成后替换旧 RDB │ │ │ COW) │ │ │ └──────────┘ │ └──────────────────────────────────────────┘fork Copy-On-Write写时复制是 RDB 不阻塞主进程的关键fork() 瞬间 ┌─────────────┐ ┌─────────────┐ │ 父进程 │ │ 子进程 │ │ 内存页表 │ ─────→│ 共享父进程 │ │ key1val1 │ │ 内存页表 │ │ key2val2 │ │ (只读共享) │ └─────────────┘ └─────────────┘ 子进程开始写 RDB 文件时读共享内存不阻塞父进程。 当父进程收到写请求要修改数据时 ┌─────────────┐ ┌─────────────┐ │ 父进程 │ │ 子进程 │ │ key1val1 │ │ key1val1 │ ← 子进程读的是旧数据快照 │ key2val2 │ │ key2val2 │ 父进程改了谁谁被复制 │ └─ 修改 key1 │ │ │ │ 复制 key1 页 →│ │ │ └─────────────┘ └─────────────┘✅父进程修改数据时被修改的内存页会复制一份给父子进程各自独立子进程始终持有 fork 瞬间的快照。2.2 RDB 的触发方式触发方式命令/场景是否阻塞主进程说明手动 SAVESAVE✅阻塞前台生成 RDB期间 Redis 不处理任何请求手动 BGSAVEBGSAVE❌ 不阻塞fork 子进程后台生成推荐手动方式自动触发配置文件 save 规则❌ 不阻塞满足条件时自动 BGSAVE关闭时触发shutdown 命令❌ 不阻塞正常关闭时自动生成 RDB主从复制全量复制❌ 不阻塞从节点连接时主节点可能生成 RDB# 手动触发127.0.0.1:6379SAVE OK# 阻塞式生产环境慎用127.0.0.1:6379BGSAVE Background saving started# 后台执行推荐127.0.0.1:6379LASTSAVE(integer)1716100500# 查看最近一次成功生成 RDB 的时间戳2.3 RDB 文件结构┌──────────┬──────────┬──────────┬──────────┬──────────┬──────────┐ │ MAGIC │ VERSION │ AUX │ DB │ DB │ EOF │ │ REDIS │ 0009 │ 字段 │ 数据 │ 数据 │ 标记 │ │ │ │ │ │ │ │ │ 5字节 │ 4字节 │ 键值对 │ n个 │ ... │ 8字节 │ │ │ │ 元信息 │ 键值对 │ │ 校验和 │ └──────────┴──────────┴──────────┴──────────┴──────────┴──────────┘MAGIC文件头标识 “REDIS”VERSIONRDB 文件格式版本号目前 9AUX辅助字段如 Redis 版本、内存占用等元信息DB 数据实际的键值对数据按数据库编号分组存储EOF 校验和结束标记 8 字节 CRC64 校验2.4 配置与实战# redis.conf ── RDB 相关配置# ───── 自动触发规则 ─────# 格式save 秒数 修改次数# 以下三条规则满足任意一条即触发 BGSAVEsave9001# 900 秒15分钟内至少有 1 个 key 变化save30010# 300 秒5分钟 内至少有 10 个 key 变化save6010000# 60 秒1分钟 内至少有 10000 个 key 变化# 示例禁用 RDB注释掉所有 save 行或配置 save # save # ───── 文件名和路径 ─────dbfilename dump-6379.rdb# RDB 文件名同一台机器用不同端口区分dir/data/redis# RDB 和 AOF 文件的存储目录# ───── 性能相关 ─────stop-writes-on-bgsave-erroryes# BGSAVE 失败时是否停止写入rdbcompressionyes# 是否压缩 RDB 文件LZF 压缩rdbchecksumyes# 是否使用 CRC64 校验和生产建议给 RDB 文件按端口命名比如dump-6379.rdb一台机器部署多个 Redis 实例时不会互相覆盖。2.5 RDB 优缺点优点缺点文件紧凑适合备份和灾难恢复可直接 scp 传输可能丢数据——两次快照之间的数据全部丢失恢复速度极快直接加载到内存比 AOF 快 10 倍以上fork 子进程可能耗时大数据量时子进程写 RDB主进程性能影响小COW 机制fork 期间如果父进程有大写入COW 会导致内存翻倍单个文件迁移、复制非常方便无法做到实时持久化RDB 是定时快照3. AOF 持久化3.1 基本原理AOF 的核心思想把每条写命令都追加到文件末尾。┌────────────────────────────────────────────┐ │ AOF 写入流程 │ │ │ │ 客户端发 SET key value │ │ ↓ │ │ ① Redis 执行命令修改内存数据 │ │ ↓ │ │ ② 将命令追加到 server.aof_buf缓冲区 │ │ ↓ │ │ ③ 根据 appendfsync 策略决定何时 fsync 到磁盘 │ │ ↓ │ │ ④ 写入磁盘的 AOF 文件 │ └────────────────────────────────────────────┘# AOF 文件里存的是啥看看就知道了127.0.0.1:6379SET name张三OK127.0.0.1:6379INCR counter(integer)1127.0.0.1:6379RPUSH list a b c(integer)3AOF 文件内容纯文本 Redis 协议格式*3 ← * 表示数组3 表示 3 个元素 $3 ← $ 表示字符串3 表示长度 SET ← 命令名 $4 name $6 张三 *2 $4 INCR $7 counter *3 $5 RPUSH $4 list $1 a $1 b $1 c AOF 文件是纯文本的 Redis 协议格式可以直接用cat查看也可以手动修改不推荐甚至可以用redis-check-aof修复损坏的 AOF 文件。3.2 AOF 的三种写回策略这是面试常考的点——appendfsync参数# redis.confappendfsync always# 每次写命令都 fsyncappendfsync everysec# 每秒 fsync 一次默认appendfsync no# 由操作系统决定何时刷盘appendfsync过程数据安全性性能always每执行一条写命令立即写入磁盘最多丢 1 条命令最安全最慢约 10,000 ops/severysec每秒将缓冲区 fsync 到磁盘一次最多丢 1 秒数据快约 50,000 ops/sno由操作系统调度刷盘通常 30 秒可能丢大量数据最快OS 自行优化合并┌─────────────────────────────────────────────────────┐ │ 三种 appendfsync 策略对比时间线 │ │ │ │ always: │ │ SET a 1 ──fsync──→ SET b 2 ──fsync──→ SET c 3 │ │ 磁盘 磁盘 磁盘 │ │ │ │ everysec: │ │ SET a 1 ──→ SET b 2 ──→ SET c 3 ──fsync──→ ... │ │ 缓冲区 磁盘每秒一次 │ │ │ │ no: │ │ SET a 1 ──→ SET b 2 ──→ ... ──→ ... ──→ fsync │ │ 缓冲区 OS 决定何时写 │ └─────────────────────────────────────────────────────┘推荐生产环境用everysec——性能和安全的折中最多丢 1 秒数据。3.3 AOF 重写机制AOF 是追加写入文件会无限膨胀。比如# 对同一个 key 操作 1000 次INCR counter# AOF 记录这条INCR counter# AOF 记录这条...# 999 条重复INCR counter# AOF 记录这条1000 条 INCR 命令 → 最终结果 SET counter 1000AOF 重写就是把内存里的数据重新生成一份最简的 AOF 文件AOF 重写前1000 条 INCR INCR counter INCR counter INCR counter ...997条 INCR counter ↓ 重写读取内存中的 counter 当前值 AOF 重写后1 条命令 SET counter 1000AOF 重写流程BGREWRITEAOF┌─────────────────────────────────────────────────────┐ │ AOF 重写流程 │ │ │ │ ① 触发条件满足配置或手动 │ │ ↓ │ │ ② 父进程 fork 一个子进程 │ │ ↓ │ │ ③ 子进程根据当前内存数据生成新的 AOF 文件 │ │ ↓ │ │ ④ 在此期间父进程继续处理请求 │ │ ┌─────────────────────────────────┐ │ │ │ 写命令 → 旧的 AOF 缓冲区正常写入│ │ │ │ → AOF 重写缓冲区增量 │ │ │ └─────────────────────────────────┘ │ │ ↓ │ │ ⑤ 子进程重写完成后通知父进程 │ │ ↓ │ │ ⑥ 父进程将 AOF 重写缓冲区的增量数据写入新文件 │ │ ↓ │ │ ⑦ 原子替换新 AOF 文件 → 覆盖旧文件 │ └─────────────────────────────────────────────────────┘AOF 重写的触发方式# 手动触发127.0.0.1:6379BGREWRITEAOF Background append onlyfilerewriting started# redis.conf ── 自动触发配置auto-aof-rewrite-percentage100# 当前 AOF 文件比上次重写时增长 100% 时触发auto-aof-rewrite-min-size 64mb# AOF 文件至少达到 64MB 才触发防止小文件频繁重写# 例子上次重写后 AOF 为 64MB当前 128MB → 增长 100% → 触发重写3.4 配置与实战# redis.conf ── AOF 相关配置# 开启 AOF默认关闭appendonlyyes# AOF 文件名appendfilenameappendonly-6379.aof# 写回策略推荐 everysecappendfsync everysec# AOF 重写配置auto-aof-rewrite-percentage100auto-aof-rewrite-min-size 64mb# 重写期间是否 fsync# 如果设为 yes重写期间每写一部分就 fsync安全但慢# 设为 no重写期间不额外 fsync快但可能丢数据no-appendfsync-on-rewrite no# 加载 AOF 时是否忽略截断的最后一条不完整命令# Redis 宕机可能导致 AOF 末尾不完整设为 yes 则尽力恢复aof-load-truncatedyes3.5 AOF 优缺点优点缺点数据安全性高everysec 最多丢 1 秒always 丢 1 条相同数据量下AOF 文件比 RDB 大得多文本协议 vs 二进制AOF 文件可读纯文本 Redis 协议便于排查问题恢复速度慢需要逐条执行命令重建数据支持后台重写避免文件无限膨胀同样数据量下AOF 比 RDB 重写/加载慢AOF 文件可手动编辑误操作时可以删最后一条命令—4. RDB vs AOF 全面对比对比维度RDBAOF文件格式二进制压缩文本Redis 协议写入方式定时全量快照实时追加写命令数据安全性可能丢两次快照间全部数据everysec 丢 1 秒always 丢 1 条恢复速度极快直接加载到内存慢逐条 redo 命令文件体积小压缩大纯文本文件可读性不可读可读可编辑对性能影响fork COW大实例 fork 耗时everysec 影响很小备份便利性好单个文件可离线复制一般文件大但可用重写压缩持久化粒度分钟级快照秒级/命令级是否容易损坏二进制损坏难修复文本损坏可修复redis-check-aof如何选择┌──────────────────────────────────────┐ │ 选择策略 │ │ │ │ 能接受丢几分钟数据 │ │ ├── ✅ 是 → 只用 RDB最简单 │ │ └── ❌ 否 → 需要 AOF │ │ │ │ 对恢复速度有要求 │ │ ├── ✅ 是 → 推荐 RDB AOF 混用 │ │ └── ❌ 否 → AOF 足够 │ │ │ │ 内存很大 10GBfork 慢 │ │ ├── ✅ 是 → 考虑 RDB 调大 save 间隔 │ │ │ 或只用 AOF省去 fork 开销 │ │ └── ❌ 否 → 都行 │ └──────────────────────────────────────┘5. Redis 4.0 混合持久化从 Redis 4.0 开始支持RDB AOF 混合持久化——结合两者优点。# redis.confaof-use-rdb-preambleyes工作原理混合持久化 AOF 文件结构 ┌──────────────────────────────────────┐ │ ┌────────────────────────┐ │ │ │ RDB 格式数据 │ ← 重写时│ │ │ (内存快照的二进制数据) │ 生成 │ │ └────────────────────────┘ │ │ │ │ ┌────────────────────────┐ │ │ │ AOF 增量命令 │ ← 重写后│ │ │ (以 Redis 协议格式) │ 增量 │ │ └────────────────────────┘ │ └──────────────────────────────────────┘重写时的行为BGREWRITEAOF 不再生成纯文本 AOF而是先生成 RDB 格式的快照写入 AOF 文件然后后续的增量写命令以 AOF 格式追加。恢复时的行为先加载 RDB 部分极快再执行 AOF 增量命令补上 RDB 快照之后的数据纯 RDB纯 AOF混合持久化恢复速度极快慢快RDB 部分秒级数据精度分钟级秒级秒级文件体积最小大中RDB 格式压缩了历史数据兼容性所有版本所有版本Redis 4.0生产推荐Redis 4.0 开启混合持久化——既有 RDB 的恢复速度又有 AOF 的数据安全性。6. 数据恢复流程与优先级Redis 重启时加载持久化文件的完整流程┌──────────────────┐ │ Redis 启动 │ └────────┬─────────┘ ↓ ┌──────────────────────────────┐ │ 检查是否有 AOF 文件 │ │ 判断条件appendonly yes │ │ appendonly.aof 文件存在 │ └──────────┬───────┬───────────┘ │ │ 是 │ │ 否 ↓ ↓ ┌─────────────────┐ ┌─────────────────┐ │ 加载 AOF 文件 │ │ 检查是否有 RDB │ │ 重放所有写命令 │ │ 文件 │ │ 恢复内存数据 │ └────────┬────────┘ └────────┬────────┘ │ ↓ ↓ ┌──────────────┐ ┌──────────────┐ │ 加载成功 ✅ │ │ 加载 RDB 文件 │ └──────────────┘ └──────────────┘ ↓ ┌──────────────┐ │ 加载成功 ✅ │ └──────────────┘优先级AOF RDB为什么 AOF 优先级更高因为 AOF 的数据通常比 RDB 更新秒级 vs 分钟级。但如果开启了混合持久化AOF 文件里包含了 RDB 快照部分加载 RDB 部分极快再补 AOF 增量。7. 面试高频问答问题参考答案要点难度Redis 为什么快还做持久化Redis 是内存数据库进程退出数据就没有了。持久化是为了数据安全和灾难恢复重启时从磁盘重新加载。不用持久化的场景纯缓存不需要开⭐⭐RDB 的 BGSAVE 为什么几乎不阻塞主进程因为fork Copy-On-Write写时复制。fork 创建子进程共享父进程内存页表子进程将内存数据写入 RDB 文件。父进程修改数据时被修改的内存页会复制一份给子进程持有旧值。子进程始终持有 fork 瞬间的完整快照⭐⭐⭐⭐RDB 的 fork 有什么风险①fork 耗时Redis 内存越大 fork 越慢10GB 实例可能 fork 几百毫秒②COW 内存膨胀fork 后父进程大量写入COW 可能导致内存峰值是平时的 2 倍③ 如果stop-writes-on-bgsave-error yes磁盘满了写不了 RDB 时Redis 会拒绝写入⭐⭐⭐⭐AOF 的三种写回策略怎么选always每次写命令都 fsync最安全最慢约 1w ops/s。everysec每秒 fsync 一次最多丢 1 秒数据约 5w ops/s。noOS 决定刷盘时机可能丢大量数据。生产推荐 everysec⭐⭐⭐AOF 文件越来越大怎么处理用AOF 重写BGREWRITEAOF。自动触发条件auto-aof-rewrite-percentage 100比上次增长 100%auto-aof-rewrite-min-size 64mb至少 64MB。重写时 fork 子进程根据当前内存生成最简 AOF不会无限膨胀⭐⭐⭐RDB 和 AOF 可以同时开吗可以。Redis 支持同时开启两者。重启时优先用 AOF 恢复数据更新。Redis 4.0 推荐混合持久化AOF 文件头部存 RDB 快照 尾部存 AOF 增量既有 RDB 的恢复速度又有 AOF 的数据安全性⭐⭐⭐主从复制中持久化有什么影响主节点做 BGSAVE 生成的 RDB 文件传给从节点完成全量同步。如果主节点关闭了持久化但有从节点主节点重启后数据为空从节点同步也会清空——主从持久化必须同时考虑⭐⭐⭐⭐Redis 挂了怎么恢复数据① 确认持久化文件存在dump.rdb / appendonly.aof② 按原配置启动 Redis③ 自动加载AOF 存在则加载 AOF否则加载 RDB④ 如果文件损坏用redis-check-rdb或redis-check-aof修复⭐⭐持久化对性能影响大吗RDB平时不影响只有定时快照时 forkfork 期间 COW 会有点 CPU 和内存开销。AOF everysec基本不影响每秒一次 fsync 由后台线程执行。主要性能杀手是 fork 耗时和 AOF always 策略⭐⭐⭐Redis 7.x 对持久化有什么新特性①Multi-Part AOF将 AOF 拆为多个文件基础文件 增量文件重写时只重写基础部分增量部分持续写入②AOF 文件更细粒度重写效率更高。整体架构更稳定减少了重写期间大量数据复制⭐⭐⭐⭐标签#Java#面试#Redis#持久化#RDB#AOF#后端开发#秋招互动话题你在生产环境用哪种持久化方案碰过什么诡异的持久化问题吗评论区见。