Redis 持久化机制详解:RDB 与 AOF

Redis 持久化机制详解:RDB 与 AOF 的原理、配置与选型

Redis 是内存数据库,数据断电即失。持久化机制是 Redis 从"缓存"走向"存储"的关键。本文深入拆解 RDB 快照和 AOF 日志两种持久化方式的底层原理、触发机制、恢复流程,并给出生产环境的选型建议。


一、为什么需要持久化?

Redis 的所有数据都存储在内存中,读写速度极快,但内存是易失性的------进程退出、服务器宕机、重启都会导致数据全部丢失。

持久化的作用就是:把内存中的数据以某种形式保存到磁盘上,重启时再从磁盘加载回内存,从而保证数据不丢。

Redis 提供了两种持久化方式:

方式 全称 核心思路
RDB Redis Database 定时对内存数据拍快照,生成二进制 dump 文件
AOF Append Only File 记录每条写命令到日志文件,重启时重放命令恢复数据

两种方式可以同时开启,互不冲突。


二、RDB 持久化

2.1 什么是 RDB?

RDB 是 Redis 的默认持久化方式 。它会在指定的时间间隔内,对内存中的数据生成一个快照(snapshot) ,以二进制格式保存到磁盘上的 dump.rdb 文件中。

复制代码
内存数据 ─fork子进程──> 遍历数据 ──> 写入临时文件 ──> 原子替换 dump.rdb

2.2 RDB 的触发方式

自动触发(save 配置)

在 redis.conf 中配置 save 规则:

conf 复制代码
save 900 1      # 900秒内至少有1个key被修改,触发快照
save 300 10     # 300秒内至少有10个key被修改,触发快照
save 60 10000   # 60秒内至少有10000个key被修改,触发快照

Redis 主进程会持续统计"距离上次快照以来被修改的 key 数量",一旦满足任意一条规则,就触发一次 RDB 快照。

手动触发
bash 复制代码
# 阻塞式:主进程直接执行快照,期间无法响应任何命令
SAVE

# 非阻塞式:fork 子进程执行快照,主进程继续处理命令(推荐)
BGSAVE
其他自动触发场景
  • 执行 SHUTDOWN 命令时,Redis 会自动执行一次 RDB
  • 主从复制时,从节点首次同步会触发主节点生成 RDB

2.3 RDB 的执行流程(BGSAVE)

复制代码
1. 主进程收到 BGSAVE 命令
2. fork() 创建子进程(Copy-on-Write 机制)
3. 子进程遍历内存数据,写入临时文件 temp-xxx.rdb
4. 写入完成后,用临时文件原子替换 dump.rdb
5. 子进程退出,向主进程发送信号
6. 主进程更新统计信息

关键点:Copy-on-Write(写时复制)

fork() 创建子进程时,并不会立即复制全部内存数据,而是让父子进程共享同一块物理内存 。只有当主进程对某页内存进行写操作时,操作系统才会把那一页复制一份给子进程。

复制代码
fork 瞬间:父子进程共享内存页
    │
    ├── 主进程写 key "name" → 操作系统复制该页 → 子进程看到的仍是旧值
    │
    └── 子进程读 key "name" → 读到的是 fork 时刻的快照数据

这意味着:

  • RDB 文件中的数据是 fork 时刻的数据快照,一致性有保障
  • 快照期间主进程可以继续处理写命令,但会产生额外的内存开销(被修改的内存页需要复制)

2.4 RDB 文件结构

RDB 文件是二进制格式,包含以下部分:

复制代码
+--------+--------+--------+--------+--------+--------+
|  REDIS | 版本   | 数据库0 | 数据库1 |  ...   |  EOF   |
|  魔数  | 号     | 的键值对 | 的键值对 |        | 校验   |
+--------+--------+--------+--------+--------+--------+
  5字节    4字节    可变长度   可变长度           1字节
  • 魔数 :REDIS(5字节),标识这是 RDB 文件
  • 版本号 :如 0011(4字节),表示 RDB 格式版本
  • 数据库数据 :每个数据库以 0xFE + 数据库编号开头,后面跟着键值对
  • EOF :0xFF(1字节),标识文件结束
  • 校验和:文件末尾的 CRC64 校验值

2.5 RDB 的优缺点

优点 缺点
文件紧凑,适合备份和灾难恢复 可能丢失最后一次快照之后的数据(最多丢失几分钟)
恢复速度极快(直接加载二进制文件) fork 子进程时,数据量大可能导致主进程短暂阻塞
子进程负责 IO,主进程性能影响小 频繁 fork 会消耗 CPU 和内存(Copy-on-Write 开销)
适合大规模数据的全量备份 不同版本的 RDB 文件格式可能不兼容

三、AOF 持久化

3.1 什么是 AOF?

AOF(Append Only File)持久化以日志形式 记录每一条写命令,Redis 重启时通过重新执行这些命令来恢复数据。

复制代码
SET name "张三"   → 追加到 appendonly.aof
HSET user:1 age 25 → 追加到 appendonly.aof
DEL temp_key      → 追加到 appendonly.aof

3.2 AOF 的三种写入策略

AOF 的写入策略由 appendfsync 配置项控制:

策略 配置值 行为 安全性 性能
always appendfsync always 每条命令都立即 fsync 到磁盘 最高,最多丢1条命令 最慢
everysec appendfsync everysec 每秒 fsync 一次(默认) 较高,最多丢1秒数据 较快
no appendfsync no 由操作系统决定何时 fsync 最低,丢数据量不可控 最快

生产环境推荐使用 everysec,在性能和安全性之间取得最佳平衡。

3.3 AOF 的执行流程

复制代码
1. 客户端发送写命令(如 SET name "张三")
2. 主进程执行命令,更新内存数据
3. 将命令追加到 AOF 缓冲区(aof_buf)
4. 根据 appendfsync 策略,将缓冲区内容写入/同步到磁盘

AOF 缓冲区(aof_buf) 是内存中的一块区域,写命令先追加到这里,再由后台线程根据策略刷盘。

3.4 AOF 重写机制(BGREWRITEAOF)

为什么需要重写?

AOF 文件会不断增大。比如对一个 key 执行 100 次 INCR,AOF 文件会记录 100 条命令,但实际上只需要记录最终值即可。

复制代码
# 重写前(100条命令)
INCR counter
INCR counter
INCR counter
...(共100条)

# 重写后(1条命令)
SET counter 100
重写流程
复制代码
1. 主进程收到 BGREWRITEAOF 命令
2. fork() 创建子进程
3. 子进程遍历当前内存数据,为每个 key 生成一条"最小命令"
4. 写入临时 AOF 文件
5. 原子替换旧 AOF 文件

重写期间的写命令处理:

重写过程中,主进程仍在处理新的写命令。这些命令需要:

  1. 追加到当前的 AOF 文件(保证 AOF 完整性)
  2. 同时写入一个重写缓冲区(aof_rewrite_buf)

子进程完成重写后,主进程会把重写缓冲区中的增量命令追加到新的 AOF 文件末尾,确保数据不丢。

复制代码
                    ┌── 当前 AOF 文件
写命令 ──> aof_buf ─┤
                    ── aof_rewrite_buf(增量缓冲)
                              │
                              ▼
                    追加到新 AOF 文件末尾
自动重写触发条件
conf 复制代码
auto-aof-rewrite-percentage 100   # AOF 文件比上次重写后增长 100% 时触发
auto-aof-rewrite-min-size 64mb    # AOF 文件至少 64MB 才触发重写

两个条件同时满足才会触发自动重写。

3.5 AOF 文件结构

AOF 文件是纯文本格式,每一行是一条 Redis 命令:

复制代码
*2
$6
SELECT
$1
0
*3
$3
SET
$4
name
$6
张三

这是 Redis 通信协议(RESP)格式:

  • *2 表示有 2 个参数
  • $6 表示下一个参数长度为 6 字节
  • 实际内容跟在后面

3.6 AOF 的优缺点

优点 缺点
数据安全性高,最多丢1秒数据(everysec) 文件体积通常比 RDB 大
可读性强,可以直接查看和编辑 恢复速度慢(需要逐条执行命令)
追加写入,磁盘顺序写性能高 重写时 fork 子进程有开销
命令格式兼容,不同版本 Redis 都能读取 相同数据的多次修改会累积记录

四、RDB vs AOF 全面对比

对比维度 RDB AOF
数据安全性 可能丢失几分钟数据 最多丢失1秒数据(everysec)
恢复速度 快(直接加载二进制) 慢(逐条重放命令)
文件体积 小(紧凑二进制) 大(文本命令日志)
性能影响 fork 时短暂阻塞 持续追加写入,影响较小
可读性 二进制,不可读 文本,可直接查看编辑
适用场景 全量备份、灾难恢复 数据安全性要求高的场景

五、生产环境配置建议

5.1 混合持久化(推荐)

Redis 4.0+ 支持混合持久化,结合 RDB 和 AOF 的优点:

conf 复制代码
aof-use-rdb-preamble yes    # AOF 重写时使用 RDB 格式作为前缀

开启后,AOF 重写生成的文件格式为:

复制代码
+------------------+------------------+
|  RDB 二进制数据   |  AOF 增量命令    |
|  (快速加载部分)  |  (精确恢复部分)  |
+------------------+------------------+
  • 前半部分是 RDB 格式的二进制数据,加载速度极快
  • 后半部分是 AOF 格式的增量命令,保证数据完整性
  • 恢复时先加载 RDB 部分,再重放 AOF 增量部分

5.2 推荐配置

conf 复制代码
# RDB 配置
save 900 1
save 300 10
save 60 10000
dbfilename dump.rdb
dir /var/lib/redis

# AOF 配置
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-use-rdb-preamble yes    # 混合持久化

# 其他
rdbcompression yes          # RDB 文件压缩
rdbchecksum yes             # RDB 文件校验

5.3 不同场景的选型

场景 推荐方案 理由
缓存场景(数据可从 DB 重建) 关闭持久化 追求极致性能,数据丢了无所谓
读多写少(配置数据、字典数据) 仅 RDB 数据变化少,RDB 快照足够
写多读少(日志、计数器) RDB + AOF 兼顾恢复速度和数据安全
金融/订单(数据不能丢) RDB + AOF(always) 最高安全性,牺牲部分性能
大规模数据(GB 级别) RDB 为主 + AOF 辅助 RDB 恢复快,AOF 兜底

六、常见问题与排查

6.1 RDB 保存失败

复制代码
(error) MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk.

原因:磁盘空间不足、权限问题、内存不足导致 fork 失败。

解决:

bash 复制代码
# 检查磁盘空间
df -h

# 检查 Redis 日志
tail -f /var/log/redis/redis-server.log

# 临时允许写入(不推荐生产使用)
config set stop-writes-on-bgsave-error no

6.2 AOF 文件损坏

复制代码
# 使用 redis-check-aof 修复
redis-check-aof --fix appendonly.aof

6.3 恢复时选择哪个文件?

如果 RDB 和 AOF 同时开启,Redis 重启时优先加载 AOF 文件,因为 AOF 的数据通常更完整。

复制代码
启动流程:
1. 检查 AOF 文件是否存在且开启 → 加载 AOF
2. 否则检查 RDB 文件 → 加载 RDB
3. 都没有 → 空数据库启动

七、总结

核心要点 说明
RDB 是快照,AOF 是日志 RDB 定时拍照片,AOF 持续记流水
RDB 恢复快但可能丢数据 适合备份和灾难恢复
AOF 数据安全但恢复慢 适合对数据完整性要求高的场景
混合持久化是最佳实践 RDB 前缀加速加载 + AOF 增量保证完整
生产环境建议两者都开 RDB 做定期备份,AOF 做实时保护
相关推荐
一条泥憨鱼3 小时前
【Redis | 黑马点评】附近商铺功能源码解读
数据库·redis·缓存
舰长1153 小时前
将百万数据插入到 Redis,有哪些实现方案?
数据结构·redis·开源
bksczm5 小时前
Redis数据结构之hash
数据结构·redis·哈希算法·1024程序员节
小南家的青蛙6 小时前
Redis的资料
redis·缓存·1024程序员节
程序员塔塔喵7 小时前
【Redis进阶篇|第十四篇】redis构建全局唯一ID
redis·全局唯一id
小南家的青蛙7 小时前
华为云DCS全产品对比
redis·1024程序员节
java_nnnn9 小时前
Redis 核心特性与应用场景:从底层原理到分布式系统应用
数据库·redis·1024程序员节
余槐i9 小时前
开虚拟线程后接口反而更慢:JDK 21 synchronized 锁住载体线程的排查
java·spring boot·redis·mysql·性能优化
啊哈一半醒10 小时前
Redis 三大缓存问题:缓存穿透、缓存击穿、缓存雪崩
运维·redis·1024程序员节