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 # 工作目录
# 优点:文件小、恢复快、备份容易
# 缺点:两次快照间的数据可能丢失SAVE 和 BGSAVE 的区别很关键: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 可能丢几分钟数据(看 save 规则);AOF(everysec)最多丢 1 秒。AOF 胜。
- 文件大小:RDB 是紧凑二进制,小;AOF 是文本命令,大(重写后会缩小)。RDB 胜。
- 恢复速度:RDB 直接加载二进制,快;AOF 要重放每条命令,慢(差几倍到几十倍)。RDB 胜。
- 性能影响:RDB 是周期性 fork,平时无开销;AOF 每条写命令追加日志,持续开销(但 everysec 下很小)。RDB 略胜。
- 可读性:RDB 是二进制,不可读;AOF 是文本协议,可读可手动修复。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 发布订阅 →