Redis 持久化:RDB 与 AOF

Redis 的所有数据放在内存里,听起来"断电就全没"。Redis 提供了两种持久化机制把内存数据写到硬盘:RDB(快照)和 AOF(日志)。本篇讲清两者的原理、配置、对比,以及生产环境该怎么选。

1. 为什么需要持久化

虽然 Redis 常被当成"缓存"——理论上丢了也能从数据库重建,但实际生产中,Redis 通常存了不可重建的数据:用户会话、计数器、排行榜、消息队列。这些数据丢了会导致用户被强制下线、点赞数清零、订单丢失。所以持久化几乎是所有生产 Redis 的必备配置

持久化要做两件事:把数据写到硬盘(防断电),和把数据保留多个版本(防误删)。RDB 和 AOF 解决的是第一个,第二个要靠"定时备份 + 异地存储"。

2. RDB:周期性快照

RDB(Redis Database)是把当前内存里的所有数据写成一个二进制快照文件 dump.rdb。触发时机有自动(save 规则)和手动(SAVE / BGSAVE)两种。

# RDB(Redis Database):周期性全量快照
# 配置文件 redis.conf 里的 save 规则:
save 900 1     # 900 秒内至少 1 个 key 改动,触发快照
save 300 10    # 300 秒内至少 10 个 key 改动,触发快照
save 60 10000  # 60 秒内至少 10000 个 key 改动,触发快照
# save ""       # 写空字符串表示禁用 RDB

# 手动触发快照:
# 1. SAVE:阻塞主线程,期间 Redis 不能处理任何命令,生产慎用!
SAVE

# 2. BGSAVE:fork 子进程后台写,主线程继续服务(推荐)
BGSAVE
# 返回: Background saving started
LASTSAVE              # 查看最后一次快照的时间戳

# 生成的文件名(默认 dump.rdb,在 Redis 工作目录)
dbfilename dump.rdb
dir /var/lib/redis    # 工作目录

# 优点:文件小、恢复快、备份容易
# 缺点:两次快照间的数据可能丢失

SAVEBGSAVE 的区别很关键:SAVE 在主线程里执行,期间 Redis 完全不能处理任何客户端命令——大实例可能阻塞几十秒,生产绝对不要用。BGSAVE 通过 fork 一个子进程在后台写,主线程不受影响,这是生产推荐的写法

3. BGSAVE 的原理:fork + COW

理解 BGSAVE 必须先懂 Linux 的 Copy-On-Write(COW)机制,这是 Redis 持久化的基石。

# BGSAVE 的原理(fork + COW)
# 1. 主进程 fork() 出一个子进程
# 2. 子进程把内存里所有数据按二进制格式写入 .rdb 文件
# 3. 写完后替换旧文件
# 4. 子进程退出,主进程继续处理客户端命令

# 关键:Linux 的 COW(Copy-On-Write)
# fork 时子进程和主进程共享同一份内存页;
# 主进程要修改某页时,内核才复制一份给它。
# 所以大实例 BGSAVE 期间内存使用可能短时上涨,
# 生产环境要预留 50% 左右的余量。

# INFO 命令查看 RDB 状态
INFO persistence
# rdb_last_bgsave_status:ok
# rdb_last_save_time:1700000000
# rdb_last_bgsave_time_sec:5
# ...

关键:fork 时子进程和主进程"共享"同一份内存页(不复制),只有当主进程要修改某页时,内核才真的复制一份。所以 BGSAVE 期间内存使用可能短时上涨——如果写非常密集,大量页被复制,内存峰值可能接近翻倍。生产 Redis 服务器内存利用率建议不超过 50%~60%,留出 COW 余量

4. AOF:追加日志

AOF(Append Only File)是把每条写命令追加到日志文件。它不存数据快照,而是存"如何到达当前状态"的全部命令序列——类似 MySQL 的 binlog。

# AOF(Append Only File):追加每条写命令到日志
appendonly yes            # 开启 AOF
appendfilename "appendonly.aof"
appendfsync everysec      # 三种刷盘策略

# 三种 appendfsync 选项对比:
# always    : 每条写命令都 fsync,最安全但最慢(吞吐降百倍)
# everysec  : 每秒 fsync 一次(默认,推荐),最多丢 1 秒数据
# no        : 由操作系统决定何时 fsync,性能好但数据安全无保证

# AOF 文件是文本协议格式,可直接阅读:
# (打开 appendonly.aof 看到的内容示例)
*2
$6
SELECT
$1
0
*3
$3
SET
$4
name
$5
hello

# 触发 AOF 重写(压缩历史命令)
BGREWRITEAOF
# 重写:扫描当前内存,生成最小命令集
# 例:历史上对同一个 key SET 了 100 次,重写后只保留最后一次

appendfsync 三个选项是性能 vs 数据安全的权衡:always 最安全但慢到几乎不能用;no 最快但断电可能丢几十秒数据;everysec 是默认推荐——既保证最多丢 1 秒,性能损失也微乎其微。99% 的生产环境都用 everysec

5. AOF 重写:压缩历史

AOF 的问题:文件会越来越大——同一个 key 被 SET 1000 次,日志里就有 1000 条命令,但当前状态只是最后一次。Redis 用重写(rewrite)解决这个问题。

# AOF 重写配置(自动触发)
auto-aof-rewrite-percentage 100   # 文件大小翻倍时触发
auto-aof-rewrite-min-size 64mb    # 文件至少 64MB 才考虑重写

# 重写过程:
# 1. 主进程 fork 子进程
# 2. 子进程把内存当前状态"重新生成一份最小命令集"
#    写入临时文件 appendonly.aof.tmp
# 3. 重写期间,新来的写命令同时写入旧 AOF 和"重写缓冲区"
# 4. 子进程写完后,主进程把缓冲区的命令追加到新 AOF
# 5. 替换旧文件,完成

# 重写的好处:
# - 文件变小(去除冗余命令,如多次改同一 key)
# - 恢复更快(重放命令少)
# - 节省硬盘空间

# 风险:
# - 重写期间内存和 CPU 双倍开销(主进程 + 子进程)
# - 大实例重写可能造成短时延迟抖动
# 生产建议:放业务低峰期、限制重写频率

重写的过程很像 BGSAVE:fork 子进程,子进程扫描当前内存生成"最小命令集"写入临时文件,期间新命令写入"重写缓冲区"避免丢失,完成后替换旧文件。重写让 AOF 文件保持紧凑,恢复速度大幅提升。

注意重写的代价:fork 大实例很慢(毫秒到秒级)、内存翻倍、CPU 上升。生产建议把重写放在业务低峰期,或限制重写频率(避免短时间内频繁触发)。

6. 混合持久化(Redis 4.0+)

理解了 RDB 和 AOF,你会发现各有优劣。Redis 4.0 引入混合持久化,把两者优点结合:

# Redis 4.0+ 引入"混合持久化"
aof-use-rdb-preamble yes   # 默认开启

# 开启后,AOF 重写时新文件的前半段是 RDB 二进制格式,
# 后半段才是增量 AOF 命令。
# 恢复时:先加载 RDB 部分(快),再重放 AOF 部分(少量)。

# 好处:兼顾 RDB 的快速恢复 和 AOF 的数据安全。
# 这是当前生产环境的主流推荐方案。

# 在 redis.conf 里的完整持久化配置示例:
save 900 1
save 300 10
save 60 10000
appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

混合持久化是当前生产环境的主流推荐——既享受 RDB 的快速恢复,又有 AOF 的数据安全(最多丢 1 秒)。Redis 5.0 之后默认开启,基本不用操心。

7. RDB vs AOF 怎么选

下面这张对照表总结了两者差异:

典型选择:纯缓存场景(数据能重建)只用 RDB 或都关;关键业务(不能丢数据)两者都开 + 混合持久化;极致性能、能容忍丢数据只用 AOF + appendfsync no 或干脆关闭持久化。

8. 备份与恢复

# 数据恢复流程(重启 Redis)
# 1. 关闭 Redis
redis-cli shutdown nosave   # nosave 表示不触发最后一次 save

# 2. 把备份文件(dump.rdb 或 appendonly.aof)放到 dir 配置的目录

# 3. 启动 Redis
redis-server /etc/redis/redis.conf
# Redis 启动时会自动加载 .rdb 或 .aof 文件,把数据恢复到内存

# 优先级:如果同时存在 AOF 和 RDB,AOF 优先(AOF 数据更全)

# 备份策略建议:
# 1. 定期把 dump.rdb 复制到对象存储(oss/s3)
# 2. 关键业务同时开 AOF + RDB
# 3. 备份不同时段的多个版本(防误删)
# 4. 定期演练恢复(光备份不演练等于没备份)

# 检查 RDB 文件内容(分析工具)
redis-check-rdb /var/lib/redis/dump.rdb
redis-check-aof /var/lib/redis/appendonly.aof

关于"备份":持久化只解决"机器没坏,只是重启",不解决"机器坏了 / 误删数据"。生产环境必须配合定期把 .rdb / .aof 文件复制到对象存储(oss / s3),并保留多个历史版本——因为误删(FLUSHALL)会被持久化到文件,如果你只有一个最新备份,误删也就"被备份了"。"演练恢复"同样重要:很多团队的备份从来没真正恢复过,等出事才发现备份根本不能用。

小结

RDB 是周期性快照(文件小、恢复快,可能丢数据);AOF 是命令日志(数据全、可读,文件大、恢复慢);混合持久化是两者的结合(当前推荐)。生产环境关键是"理解 fork+COW 的内存开销、appendfsync 的策略选择、备份与演练的完整流程"。

← 上一篇 Redis 有序集合命令

下一篇 Redis 发布订阅

✈️💬