Chapter 07

Redis 持久化:RDB 与 AOF

内存数据如何安全落地磁盘——RDB 快照、AOF 追加写、混合持久化的设计权衡

为什么需要持久化

Redis 是内存数据库,进程崩溃或服务器断电后,内存数据全部消失。持久化机制将内存数据写入磁盘,使 Redis 在重启后能恢复数据,扮演"不那么纯粹"的内存数据库角色。

RDB:快照持久化

RDB(Redis Database Backup)在指定时间点将内存中的全部数据以二进制格式快照.rdb 文件。类似数据库的全量备份。

RDB fork-copy-on-write 机制 Redis 主进程(继续处理命令) ↓ fork() 子进程(遍历内存,写入 .rdb) 共享父进程内存页(写时复制) 如果父进程修改某页内存: 父进程 ──复制该页──▶ 新内存页(父进程使用) 原内存页(子进程继续读) 结论:RDB 期间父进程可正常工作,但大量写操作会导致内存翻倍

RDB 触发方式

自动触发(save 配置)

# redis.conf
# 900秒内有1次写操作
save 900 1
# 300秒内有10次写操作
save 300 10
# 60秒内有10000次写操作
save 60 10000
# 关闭 RDB
save ""

手动触发

# BGSAVE:异步(推荐)
# fork 子进程后立即返回
BGSAVE

# SAVE:同步(阻塞,慎用)
# 会阻塞 Redis 直到完成
SAVE

# 查看最后一次 RDB 保存时间
LASTSAVE

RDB 配置项

# redis.conf 关键配置
dbfilename dump.rdb              # RDB 文件名
dir /var/lib/redis               # 存储目录
rdbcompression yes               # 使用 LZF 压缩(节省磁盘,略增 CPU)
rdbchecksum yes                  # 文件末尾加 CRC64 校验和
stop-writes-on-bgsave-error yes  # BGSAVE 失败时停止写操作(保护数据一致性)

AOF:追加写日志

AOF(Append Only File)将每条写命令以 RESP 格式追加到 .aof 文件末尾,类似 MySQL 的 binlog。Redis 重启时重放所有命令来恢复数据。

AOF 文件格式(RESP 协议) *3 ← 3 个参数 $3 ← 第1个参数长度3字节 SET ← 命令 $4 ← 第2个参数长度4字节 name ← key $5 ← 第3个参数长度5字节 Redis ← value

AOF 同步策略(fsync)

AOF 写入分两步:先写到操作系统 page cache,再由 fsync 刷入磁盘。同步策略决定数据安全性和性能的权衡:

appendfsync 配置fsync 时机数据安全性能影响
always每条命令执行后立即同步最高(几乎不丢数据)最大(每次写磁盘)
everysec(推荐)每秒同步一次高(最多丢1秒数据)中(异步后台)
no由操作系统决定(通常30秒)低(可能丢失30秒)最小

AOF 重写:压缩日志文件

AOF 文件会持续增大(如对同一 key 做了 1000 次 SET,文件里有 1000 条记录,但只有最后一条有效)。AOF 重写将内存当前状态转换为最小命令集:

AOF 重写前后对比 重写前 AOF(冗余): SET counter 1 SET counter 2 SET counter 3 ... (1000次) SET counter 1000 重写后 AOF(精简): SET counter 1000 ← 一条命令表达最终状态
# redis.conf AOF 配置
appendonly yes               # 开启 AOF
appendfilename "appendonly.aof"
appendfsync everysec         # 推荐:每秒同步
no-appendfsync-on-rewrite no # 重写期间是否暂停同步

# AOF 自动重写触发条件
auto-aof-rewrite-percentage 100  # 文件比上次重写后增长100%时触发
auto-aof-rewrite-min-size 64mb  # 最小64MB才触发重写

# 手动触发 AOF 重写
BGREWRITEAOF

混合持久化(推荐生产配置)

Redis 4.0 引入混合模式:AOF 重写时,文件头部写入 RDB 格式的全量快照,尾部追加增量 AOF 命令。兼顾了 RDB 的快速恢复和 AOF 的数据安全。

混合持久化文件结构 ┌───────────────────────────────────────────────┐ │ appendonly.aof │ │ ┌──────────────────────────────────────────┐ │ │ │ RDB 格式数据(某时刻的完整快照) │ │ │ └──────────────────────────────────────────┘ │ │ ┌──────────────────────────────────────────┐ │ │ │ AOF 格式增量命令(快照之后的写操作) │ │ │ └──────────────────────────────────────────┘ │ └───────────────────────────────────────────────┘ 恢复时:先加载 RDB(快)→ 再重放增量 AOF(少)
# 开启混合持久化
aof-use-rdb-preamble yes  # Redis 7.x 默认已开启

数据恢复流程

Redis 启动时的持久化文件加载顺序 Redis 启动 AOF 开启? ├── YES ──▶ 加载 AOF 文件(包含 RDB+AOF 混合内容) └── NO ──▶ 加载 RDB 文件(如果存在) 加载完成,开始对外服务 注意:如果 AOF 和 RDB 都存在,优先使用 AOF(数据更新)

持久化性能影响分析

方案写性能影响恢复速度数据安全文件大小
不持久化无影响N/A(重启丢数据)最低N/A
RDB only低(fork 瞬间暂停微秒~毫秒)最快低(可能丢几分钟)最小(压缩二进制)
AOF everysec中(后台 fsync)慢(重放命令)高(最多丢1秒)大(文本格式)
AOF always高(每次写磁盘)最高
混合模式

fork 导致主进程阻塞BGSAVEBGREWRITEAOF 在 fork 时会短暂阻塞主进程(Linux 需要复制页表)。内存越大阻塞越长——100GB 内存的 Redis 实例 fork 可能阻塞数秒!应定期监控 INFO persistence 中的 rdb_last_bgsave_time_sec,并使用内存大页(Transparent Huge Pages)前需评估其对 fork 的影响。

生产环境推荐配置

# /etc/redis/redis.conf 生产推荐

# 混合持久化
appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# RDB(作为额外备份)
save 3600 1      # 1小时有1次写则保存
save 300 100     # 5分钟有100次写则保存
rdbcompression yes
rdbchecksum yes

# 数据目录(建议独立磁盘)
dir /data/redis
dbfilename dump.rdb
# 检查持久化状态
redis-cli INFO persistence | grep -E "rdb_|aof_"

# 关键指标说明:
# rdb_last_bgsave_status: ok        ← 最后一次 BGSAVE 是否成功
# rdb_last_bgsave_time_sec: 2       ← 上次 BGSAVE 耗时(秒)
# aof_current_size: 52428800        ← AOF 当前大小(字节)
# aof_rewrite_in_progress: 0        ← 是否正在重写