Redis 持久化
问题
Redis 有哪些持久化方式?RDB 和 AOF 的区别是什么?如何选择持久化策略?
答案
持久化方式概览
| 方式 | 原理 | 安全性 | 性能 |
|---|---|---|---|
| RDB | 定时生成内存快照 | 可能丢失最后一次快照后的数据 | 对运行时性能影响小 |
| AOF | 记录每条写命令 | 最多丢失 1 秒数据 | 写操作有一定开销 |
| 混合持久化 | RDB + AOF 结合 | 兼顾两者优点 | Redis 4.0+ 推荐 |
RDB(Redis Database)
RDB 将某个时刻的内存快照以二进制文件的形式保存到磁盘(默认文件名 dump.rdb)。
触发方式
自动触发(redis.conf)
# save <秒数> <修改次数>
save 900 1 # 900 秒内至少 1 次修改
save 300 10 # 300 秒内至少 10 次修改
save 60 10000 # 60 秒内至少 10000 次修改
手动触发
SAVE # 同步执行,阻塞主进程(生产禁用)
BGSAVE # 后台异步执行,fork 子进程
BGSAVE 执行流程
Copy-On-Write(COW)
fork 后父子进程共享相同的内存页。当主进程修改数据时,操作系统会复制对应的内存页给子进程,子进程仍然写入 fork 时刻的快照。这就是写时复制(COW) 机制。
COW 的风险:如果 fork 后主进程大量写入,需要复制大量页面,可能导致内存翻倍。
RDB 优缺点
| 优点 | 缺点 |
|---|---|
| 文件紧凑,适合备份和传输 | 两次快照之间的数据可能丢失 |
| 恢复速度快(直接加载二进制) | fork 子进程时大内存实例可能卡顿 |
| 对运行时性能影响小 | 数据安全性不如 AOF |
AOF(Append Only File)
AOF 将每条写命令追加到日志文件(默认 appendonly.aof),重启时通过重放命令恢复数据。
开启 AOF
redis.conf
appendonly yes
appendfilename "appendonly.aof"
写入流程
三种刷盘策略
| 策略 | 行为 | 数据安全 | 性能 |
|---|---|---|---|
always | 每条命令都 fsync | 最高(不丢数据) | 最低 |
everysec(默认) | 每秒 fsync | 最多丢 1 秒 | 折中 |
no | 由操作系统决定 | 可能丢较多数据 | 最高 |
AOF 重写
随着写命令不断追加,AOF 文件会越来越大。AOF 重写 根据当前内存数据生成最精简的命令集,替换旧文件。
触发 AOF 重写
BGREWRITEAOF # 手动触发
# 自动触发条件(redis.conf)
auto-aof-rewrite-percentage 100 # 文件增长超过上次重写后的 100%
auto-aof-rewrite-min-size 64mb # 最小文件大小
重写过程中新的写命令会同时写入旧 AOF 文件和AOF 重写缓冲区,确保重写期间数据不丢失。
AOF 优缺点
| 优点 | 缺点 |
|---|---|
| 数据安全性高(最多丢 1 秒) | 文件体积比 RDB 大 |
| 人类可读(文本格式) | 恢复速度比 RDB 慢(需重放命令) |
| 支持重写压缩 | 写操作有额外开销 |
混合持久化(Redis 4.0+)
开启混合持久化
aof-use-rdb-preamble yes # 默认开启(Redis 5.0+)
AOF 重写时,前半部分以 RDB 格式写入(内存快照),后半部分以 AOF 格式追加(重写期间的增量命令)。
[RDB 二进制数据 | AOF 增量命令]
兼顾了两者的优点:
- 恢复速度快(RDB 部分直接加载)
- 数据安全性高(AOF 部分补齐增量)
RDB vs AOF 对比
| 对比维度 | RDB | AOF |
|---|---|---|
| 文件格式 | 二进制快照 | 文本命令日志 |
| 数据安全 | 可能丢几分钟数据 | 最多丢 1 秒 |
| 文件大小 | 小(压缩) | 大(命令日志) |
| 恢复速度 | 快 | 慢 |
| 性能影响 | fork 时有短暂影响 | 写操作有持续影响 |
| 适用场景 | 数据备份、灾难恢复 | 数据安全要求高 |
持久化策略选择
| 场景 | 推荐方案 |
|---|---|
| 纯缓存,丢失可接受 | 不开持久化,或只开 RDB |
| 数据安全要求高 | AOF(everysec)+ RDB 定期备份 |
| 生产环境推荐 | 混合持久化(RDB + AOF) |
| 主从架构 | 主节点 AOF,从节点 RDB 备份 |
常见面试问题
Q1: RDB 和 AOF 的区别?
答案:
核心区别三点:
- 记录内容:RDB 记录内存快照(某个时间点的全量数据),AOF 记录写命令日志(增量操作)
- 数据安全:RDB 可能丢失最后一次快照后的数据(几分钟),AOF 最多丢 1 秒(everysec 策略)
- 恢复速度:RDB 直接加载二进制快照,速度快;AOF 需要逐条重放命令,速度慢
生产环境推荐使用混合持久化(Redis 4.0+),结合两者优点。
Q2: RDB 的 BGSAVE 如何保证数据一致性?
答案:
通过操作系统的 COW(Copy-On-Write,写时复制) 机制:
- 主进程
fork()出子进程,此时父子共享相同的物理内存页 - 子进程开始遍历内存生成 RDB 文件,读取的是 fork 时刻的数据
- 主进程修改数据时,操作系统为被修改的页面创建副本,子进程仍然访问原始页面
- 所以子进程写入的是 fork 时刻的一致性快照
风险:如果 fork 后主进程写入量很大,COW 需要复制大量页面,可能导致内存使用接近翻倍。
Q3: AOF 文件太大怎么办?
答案:
通过 AOF 重写(BGREWRITEAOF) 解决。重写过程:
- fork 子进程,根据当前内存数据生成最精简的命令集
- 例如对同一个 key 的 100 次 SET 操作,重写后只保留最后一次
- 重写期间的新命令同时写入旧 AOF 和重写缓冲区
- 重写完成后,将重写缓冲区的命令追加到新 AOF 文件,原子替换旧文件
可以设置自动触发条件:文件增长超过上次重写后的 auto-aof-rewrite-percentage(默认 100%)。
Q4: Redis 重启时如何恢复数据?
答案:
恢复优先级:
- 如果开启了 AOF(
appendonly yes),优先加载 AOF 文件(数据更完整) - 如果没有 AOF,则加载 RDB 文件(
dump.rdb) - 如果使用了混合持久化,AOF 文件前半部分是 RDB 格式(快速加载),后半部分是 AOF 增量命令(补齐数据)
加载过程中如果文件损坏,可以使用 redis-check-aof --fix 或 redis-check-rdb 工具修复。
Q5: 生产环境如何配置持久化?
答案:
推荐配置:
# 开启 AOF
appendonly yes
appendfsync everysec
# 开启混合持久化
aof-use-rdb-preamble yes
# RDB 作为补充备份
save 900 1
save 300 10
# 定期将 RDB 备份到异地(crontab)
额外建议:
- 控制 Redis 内存使用量,避免 fork 时 COW 开销过大
- 主从架构中,从节点负责 RDB 备份,减少主节点压力
- 监控
latest_fork_usec(最近一次 fork 耗时),超过 1 秒需要关注