跳到主要内容

Redis 持久化

问题

Redis 的 RDB 和 AOF 持久化有什么区别?如何选择?混合持久化是什么?

答案

一、RDB(Redis Database)

快照方式:将某一时刻的全量数据保存为二进制文件(dump.rdb)。

触发方式

# 手动触发
SAVE # 阻塞主线程(生产禁用)
BGSAVE # fork 子进程后台保存(推荐)

# 自动触发(redis.conf)
save 900 1 # 900 秒内至少 1 次写入
save 300 10 # 300 秒内至少 10 次写入
save 60 10000 # 60 秒内至少 10000 次写入

BGSAVE 流程

Copy-On-Write

fork 后子进程与父进程共享内存页。只有当父进程修改某个页时,才会复制该页。所以 BGSAVE 期间额外内存开销通常很小(取决于写入频率)。

RDB 优缺点

优点缺点
文件紧凑,恢复速度快两次快照之间的数据会丢失
适合备份和灾难恢复fork 大内存时可能阻塞
对性能影响小不适合高数据安全要求

二、AOF(Append Only File)

追加日志方式:将每条写命令追加到文件末尾。

写入流程

写命令 → AOF 缓冲区 → write() 到 page cache → fsync 到磁盘

同步策略

配置 appendfsync行为数据安全性能
always每条命令都 fsync最多丢 1 条最低
everysec每秒 fsync最多丢 1 秒推荐
no不主动 fsync取决于 OS最高

AOF 重写

AOF 文件会持续增长,需要定期 重写压缩

# 手动触发
BGREWRITEAOF

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

重写原理:不是对旧 AOF 文件操作,而是根据当前内存数据 生成最少的命令集。例如:

# 重写前(100 条 INCR)
INCR counter # ×100

# 重写后(1 条 SET)
SET counter 100

三、RDB vs AOF 对比

对比项RDBAOF
数据安全可能丢失两次快照间的数据最多丢 1 秒
文件大小小(二进制压缩)大(文本命令)
恢复速度慢(重放命令)
性能影响fork 时有瞬间开销持续写入有 IO 开销
适用场景备份、灾难恢复数据安全要求高

四、混合持久化(4.0+,推荐)

aof-use-rdb-preamble yes  # 默认开启(Redis 5.0+)

AOF 重写时:先写 RDB 格式的全量数据,再追加重写期间的 AOF 增量命令:

┌──────────────────────┬────────────────┐
│ RDB 格式全量数据 │ AOF 增量命令 │
└──────────────────────┴────────────────┘

恢复时:先加载 RDB 部分(快),再重放 AOF 部分(少量命令)。

生产推荐
  1. 开启混合持久化(默认)
  2. appendfsync 设为 everysec
  3. 定期将 RDB 文件备份到异地

常见面试问题

Q1: RDB 和 AOF 可以同时开启吗?

答案
可以。同时开启时,Redis 重启 优先使用 AOF 恢复数据(因为 AOF 的数据更完整)。推荐同时开启:AOF 保证数据安全,RDB 用于备份。

Q2: fork 子进程会阻塞吗?

答案
fork 本身是需要复制页表的,如果 Redis 实例内存很大(如 20GB+),fork 可能需要几十到几百毫秒,这段时间主进程会阻塞。

优化方式:

  • 控制 Redis 实例内存不要太大(建议单实例不超过 10GB)
  • 使用 info stats 监控 latest_fork_usec 指标
  • 关闭 Transparent Huge Pages(THP)

Q3: AOF 文件损坏了怎么办?

答案

# 检查并修复 AOF 文件
redis-check-aof --fix appendonly.aof

该工具会截断 AOF 文件中最后不完整的命令,可能会丢失少量数据。所以建议同时保留 RDB 备份。


相关链接