Redis 持久化机制
2026/3/20大约 15 分钟
Redis 持久化机制
一、持久化概述
Redis 是基于内存的数据库,一旦服务重启或宕机,内存中的数据就会丢失。为了保证数据的持久性,Redis 提供了两种持久化机制:
- RDB(Redis Database):定时将内存数据快照保存到磁盘
- AOF(Append Only File):将每个写操作追加到日志文件
1.1 两种持久化方式对比
| 对比项 | RDB | AOF |
|---|---|---|
| 文件大小 | 小(二进制压缩) | 大(文本格式) |
| 恢复速度 | 快 | 慢 |
| 数据安全 | 可能丢失最后一次快照后的数据 | 最多丢失 1 秒数据 |
| 写入开销 | 低(定时触发) | 高(每次写操作) |
| 可读性 | 不可读 | 可读(RESP 协议) |
| 版本兼容 | 不同版本可能不兼容 | 兼容性好 |
| 适用场景 | 备份、灾难恢复 | 数据安全性要求高 |
二、RDB 快照持久化
2.1 RDB 工作原理
RDB 持久化是将某个时间点的内存数据生成快照保存到磁盘。
写时复制(Copy-On-Write)
RDB 使用 fork 创建子进程时,采用操作系统的写时复制机制:
- fork 时父子进程共享相同的内存页
- 当父进程修改数据时,操作系统才会复制对应的内存页
- 子进程看到的是 fork 时的数据快照
这种机制使得 fork 操作非常快,且只有被修改的数据才需要额外的内存。
2.2 触发 RDB 的方式
方式 1:手动触发
# 同步保存(阻塞主进程,生产环境禁用)
SAVE
# 异步保存(fork 子进程,推荐)
BGSAVE
# 查看最后一次 RDB 保存时间
LASTSAVE
方式 2:自动触发
在 redis.conf 中配置自动触发条件:
# 900秒内至少1次修改
save 900 1
# 300秒内至少10次修改
save 300 10
# 60秒内至少10000次修改
save 60 10000
# 禁用自动 RDB
# save ""
方式 3:其他触发场景
# 主从复制时,主节点会自动执行 BGSAVE
# 执行 SHUTDOWN 命令时会自动执行 RDB
# 执行 FLUSHALL 命令时会生成空的 RDB 文件
# 执行 DEBUG RELOAD 命令时
2.3 RDB 相关配置
# =========================
# RDB 配置
# =========================
# 自动触发条件
save 900 1
save 300 10
save 60 10000
# RDB 文件名
dbfilename dump.rdb
# RDB 文件存储目录
dir /data/redis
# RDB 保存失败时是否停止接收写入
# 建议开启,可以及时发现磁盘问题
stop-writes-on-bgsave-error yes
# 是否压缩 RDB 文件
# 压缩可减少磁盘空间,但会消耗 CPU
rdbcompression yes
# 是否校验 RDB 文件
# 开启后加载时会校验文件完整性
rdbchecksum yes
# 删除复制中使用的 RDB 文件(Redis 6.0+)
rdb-del-sync-files no
2.4 RDB 文件结构
RDB 文件格式
| 标记 | 描述 |
|---|---|
| REDIS | 5 字节魔数 "REDIS" |
| RDB Version | 4 字节版本号,如 "0009" |
| Aux Fields | 辅助字段:redis-ver、redis-bits、ctime 等 |
| DB Selector | 1 字节数据库选择器 0xFE + db_number |
| Key-Value Pairs | 键值对 |
| EOF | 1 字节结束符 0xFF |
| Checksum | 8 字节 CRC64 校验和 |
2.5 RDB 分析工具
# 使用 redis-check-rdb 检查 RDB 文件
redis-check-rdb dump.rdb
# 使用 redis-rdb-tools 分析 RDB(需要安装)
pip install rdbtools python-lzf
# 转换为 JSON 格式
rdb --command json dump.rdb > dump.json
# 分析内存使用
rdb --command memory dump.rdb --bytes 1024 > memory.csv
# 只导出指定类型的 key
rdb --command json --type string dump.rdb
# 查看大 key
redis-cli --bigkeys
2.6 RDB 的优缺点
优点:
- 文件紧凑,适合备份和灾难恢复
- 恢复大数据集时速度快于 AOF
- RDB 生成由子进程完成,对主进程影响小
- 非常适合做定期备份
缺点:
- 无法做到秒级持久化,可能丢失最后一次快照后的数据
- fork 子进程时,如果数据量大,可能导致短暂的服务暂停
- RDB 文件版本兼容性问题
三、AOF 日志持久化
3.1 AOF 工作原理
AOF 通过保存所有写命令来记录数据库状态。
AOF 文件使用 RESP(Redis Serialization Protocol)协议格式存储命令:
# SET name redis 的 AOF 格式
*3 # 命令有3个参数
$3 # 第1个参数长度为3
SET # 第1个参数
$4 # 第2个参数长度为4
name # 第2个参数
$5 # 第3个参数长度为5
redis # 第3个参数
3.2 AOF 写入策略
AOF 的 appendfsync 配置决定了数据刷盘的时机:
| 策略 | 说明 | 数据安全 | 性能 |
|---|---|---|---|
| always | 每个写命令都同步刷盘 | 最高,最多丢失一条命令 | 最慢 |
| everysec | 每秒同步一次(推荐) | 较高,最多丢失 1 秒数据 | 均衡 |
| no | 由操作系统决定何时刷盘 | 最低,可能丢失较多数据 | 最快 |
# 推荐配置
appendfsync everysec
写入流程详解
appendfsync 策略:
- always: 每次 write 后立即 fsync
- everysec: 每秒执行一次 fsync
- no: 不主动 fsync,由 OS 决定
3.3 AOF 重写机制
随着时间推移,AOF 文件会越来越大。Redis 提供了 AOF 重写机制来压缩文件:
重写工作流程
触发重写的方式
# 手动触发
BGREWRITEAOF
# 自动触发(redis.conf 配置)
# 当 AOF 文件大小比上次重写后大 100% 时触发
auto-aof-rewrite-percentage 100
# AOF 文件最小重写大小
auto-aof-rewrite-min-size 64mb
3.4 AOF 相关配置
# =========================
# AOF 配置
# =========================
# 是否开启 AOF
appendonly yes
# AOF 文件名
appendfilename "appendonly.aof"
# AOF 文件存储目录(与 RDB 共用)
dir /data/redis
# 同步策略
appendfsync everysec
# 重写期间是否禁止 fsync
# 开启可提高重写性能,但可能丢失数据
no-appendfsync-on-rewrite no
# 自动重写触发条件
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 加载 AOF 时是否忽略最后一条可能存在问题的指令
aof-load-truncated yes
# 是否使用 RDB-AOF 混合持久化(Redis 4.0+)
aof-use-rdb-preamble yes
3.5 AOF 修复与检查
# 检查 AOF 文件是否有问题
redis-check-aof appendonly.aof
# 修复损坏的 AOF 文件
redis-check-aof --fix appendonly.aof
# 修复后建议手动检查被截断的内容
# 修复会删除 AOF 文件末尾不完整的命令
3.6 AOF 的优缺点
优点:
- 数据安全性高,最多丢失 1 秒数据(everysec)
- AOF 文件是追加写入,没有寻址开销,写入性能好
- AOF 文件可读性好,便于分析和修改
- 即使文件损坏,也可以通过 redis-check-aof 工具修复
缺点:
- AOF 文件通常比 RDB 文件大
- 恢复大数据集时速度慢于 RDB
- AOF 重写期间可能影响性能
- 在极端情况下可能出现 Bug(历史版本)
四、混合持久化(Redis 4.0+)
4.1 混合持久化原理
混合持久化结合了 RDB 和 AOF 的优点:
- AOF 重写时,先以 RDB 格式写入当前数据快照
- 然后追加重写期间的增量 AOF 命令
- 恢复时先加载 RDB 部分,再执行 AOF 命令
4.2 配置混合持久化
# 开启 AOF
appendonly yes
# 开启混合持久化(Redis 4.0+,默认开启)
aof-use-rdb-preamble yes
4.3 混合持久化的优势
| 对比项 | 纯 RDB | 纯 AOF | 混合持久化 |
|---|---|---|---|
| 文件大小 | 小 | 大 | 中等 |
| 恢复速度 | 快 | 慢 | 快 |
| 数据安全 | 可能丢分钟级 | 最多丢 1 秒 | 最多丢 1 秒 |
| 可读性 | 不可读 | 可读 | 部分可读 |
五、持久化配置策略
5.1 不同场景的配置建议
场景 1:纯缓存场景
如果 Redis 仅作为缓存,数据丢失可以接受:
# 禁用 RDB
save ""
# 禁用 AOF
appendonly no
场景 2:数据安全性要求高
金融、订单等对数据安全要求高的场景:
# 开启 AOF
appendonly yes
# 每秒同步
appendfsync everysec
# 同时保留 RDB 作为备份
save 900 1
save 300 10
save 60 10000
# 开启混合持久化
aof-use-rdb-preamble yes
场景 3:主从架构
主从复制场景下的持久化配置:
# 主节点:开启 AOF 保证数据安全
appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes
# 主节点可以关闭 RDB 自动保存(复制使用 BGSAVE)
save ""
# 从节点:可以只开启 RDB,减少 I/O
# appendonly no
save 900 1
save 300 10
save 60 10000
5.2 持久化性能优化
避免频繁的 fork
# 适当调整自动保存频率
save 900 1
save 300 100
save 60 10000
# 增加 AOF 重写阈值
auto-aof-rewrite-percentage 200
auto-aof-rewrite-min-size 128mb
使用 SSD 磁盘
# 磁盘 I/O 是持久化的主要瓶颈
# 使用 SSD 可以显著提升性能
# 查看磁盘 I/O 情况
iostat -x 1
# 监控 Redis 的 fork 耗时
INFO stats | grep latest_fork_usec
合理配置内存
# 预留足够内存给 fork 操作
# 建议 maxmemory 不超过物理内存的 50%
# 因为 fork 时可能需要最多 2 倍内存
maxmemory 4gb # 假设物理内存 8GB
5.3 备份策略
# 定时备份脚本示例
#!/bin/bash
BACKUP_DIR="/data/redis/backup"
DATE=$(date +%Y%m%d_%H%M%S)
REDIS_DATA_DIR="/data/redis"
# 创建备份目录
mkdir -p $BACKUP_DIR
# 触发 BGSAVE
redis-cli BGSAVE
# 等待 BGSAVE 完成
while [ $(redis-cli LASTSAVE) == $(cat /tmp/redis_lastsave 2>/dev/null) ]; do
sleep 1
done
redis-cli LASTSAVE > /tmp/redis_lastsave
# 复制 RDB 文件
cp $REDIS_DATA_DIR/dump.rdb $BACKUP_DIR/dump_$DATE.rdb
# 复制 AOF 文件
cp $REDIS_DATA_DIR/appendonly.aof $BACKUP_DIR/appendonly_$DATE.aof
# 压缩备份
gzip $BACKUP_DIR/dump_$DATE.rdb
gzip $BACKUP_DIR/appendonly_$DATE.aof
# 删除7天前的备份
find $BACKUP_DIR -name "*.gz" -mtime +7 -delete
echo "Backup completed: $DATE"
六、数据恢复
6.1 恢复流程
6.2 恢复操作步骤
从 RDB 恢复
# 1. 停止 Redis 服务
redis-cli SHUTDOWN
# 2. 备份当前数据文件
mv /data/redis/dump.rdb /data/redis/dump.rdb.bak
# 3. 复制 RDB 备份文件
cp /backup/dump.rdb /data/redis/dump.rdb
# 4. 确保文件权限正确
chown redis:redis /data/redis/dump.rdb
# 5. 启动 Redis
redis-server /etc/redis/redis.conf
# 6. 验证数据
redis-cli DBSIZE
redis-cli INFO keyspace
从 AOF 恢复
# 1. 停止 Redis 服务
redis-cli SHUTDOWN
# 2. 检查 AOF 文件
redis-check-aof /backup/appendonly.aof
# 3. 如果有问题,修复 AOF 文件
redis-check-aof --fix /backup/appendonly.aof
# 4. 复制 AOF 文件
cp /backup/appendonly.aof /data/redis/appendonly.aof
chown redis:redis /data/redis/appendonly.aof
# 5. 启动 Redis(确保配置中 appendonly yes)
redis-server /etc/redis/redis.conf
# 6. 验证数据
redis-cli DBSIZE
6.3 RDB 和 AOF 之间的切换
从 RDB 切换到 AOF
# 1. 热启用 AOF(无需重启)
redis-cli CONFIG SET appendonly yes
# 2. 等待 AOF 文件生成
redis-cli BGREWRITEAOF
# 3. 确认 AOF 正常工作
redis-cli CONFIG GET appendonly
# 4. 修改配置文件使其永久生效
# 编辑 redis.conf,设置 appendonly yes
从 AOF 切换到 RDB
# 1. 关闭 AOF
redis-cli CONFIG SET appendonly no
# 2. 触发 RDB 保存
redis-cli BGSAVE
# 3. 修改配置文件
# 编辑 redis.conf,设置 appendonly no
七、持久化监控
7.1 关键指标监控
# 查看持久化相关信息
redis-cli INFO persistence
# 关键指标说明
# rdb_last_save_time: 最后一次 RDB 保存时间戳
# rdb_changes_since_last_save: 距上次 RDB 的修改次数
# rdb_bgsave_in_progress: 是否正在进行 BGSAVE
# rdb_last_bgsave_status: 最后一次 BGSAVE 状态
# rdb_last_bgsave_time_sec: 最后一次 BGSAVE 耗时
# aof_enabled: AOF 是否开启
# aof_rewrite_in_progress: 是否正在进行 AOF 重写
# aof_last_rewrite_time_sec: 最后一次 AOF 重写耗时
# aof_current_size: AOF 文件当前大小
# aof_base_size: AOF 重写后的基础大小
# 查看 fork 耗时
redis-cli INFO stats | grep latest_fork_usec
7.2 告警配置建议
# 监控脚本示例
#!/bin/bash
# RDB 保存失败告警
rdb_status=$(redis-cli INFO persistence | grep rdb_last_bgsave_status | cut -d: -f2 | tr -d '\r')
if [ "$rdb_status" != "ok" ]; then
echo "ALERT: RDB bgsave failed!"
fi
# AOF 写入延迟告警
aof_delayed=$(redis-cli INFO persistence | grep aof_delayed_fsync | cut -d: -f2 | tr -d '\r')
if [ "$aof_delayed" -gt 0 ]; then
echo "ALERT: AOF fsync delayed: $aof_delayed"
fi
# fork 耗时告警(超过 500ms 警告)
fork_time=$(redis-cli INFO stats | grep latest_fork_usec | cut -d: -f2 | tr -d '\r')
if [ "$fork_time" -gt 500000 ]; then
echo "ALERT: Fork time too long: ${fork_time}us"
fi
八、常见问题与解决
8.1 fork 导致的性能问题
问题:大数据量时 fork 操作导致主进程阻塞
解决方案:
# 1. 使用 SSD 磁盘
# 2. 避免在高峰期触发 BGSAVE/BGREWRITEAOF
# 3. 调整 Linux 系统参数
echo 'vm.overcommit_memory = 1' >> /etc/sysctl.conf
sysctl -p
# 4. 如果开启了 THP,建议关闭
echo never > /sys/kernel/mm/transparent_hugepage/enabled
# 5. 减少数据量或分片
8.2 AOF 文件过大
问题:AOF 文件增长过快,占用大量磁盘空间
解决方案:
# 调整重写触发条件
auto-aof-rewrite-percentage 50
auto-aof-rewrite-min-size 64mb
# 手动触发重写
# redis-cli BGREWRITEAOF
# 开启混合持久化
aof-use-rdb-preamble yes
8.3 数据恢复慢
问题:重启时数据恢复时间过长
解决方案:
# 1. 使用混合持久化
# 2. 使用 SSD 磁盘
# 3. 定期重写 AOF,减少 AOF 文件大小
# 4. 考虑分片,减少单实例数据量
九、总结
持久化方式选择
| 场景 | 推荐方案 |
|---|---|
| 纯缓存 | 关闭持久化 |
| 允许分钟级数据丢失 | 仅 RDB |
| 数据安全要求高 | AOF (everysec) + RDB 备份 |
| 兼顾安全和性能 | 混合持久化(推荐) |
| 主从架构 | 主 AOF,从 RDB |
最佳实践
- 生产环境推荐使用混合持久化
- 合理配置自动触发条件,避免频繁 fork
- 使用 SSD 磁盘提升 I/O 性能
- 定期备份持久化文件到异地
- 监控持久化状态,及时告警
- 配置足够的内存,预留 fork 开销
- 定期检查持久化文件完整性