3. Redis持久化机制:RDB快照原理、AOF日志原理、混合持久化、持久化策略选择

Redis 作为内存数据库,其数据全部存储在内存中。一旦进程退出或服务器宕机,内存中的数据将全部丢失。持久化机制是 Redis 保证数据安全的核心手段,它允许 Redis 将内存中的数据保存到磁盘,并在重启时从磁盘恢复数据。本章将深入剖析 RDB 快照、AOF 日志、混合持久化三种机制的原理与配置,并给出生产环境下的策略选择建议。

3.1 RDB 快照原理

RDB(Redis Database)持久化通过创建数据集的时间点快照(Point-in-Time Snapshot)来实现。在指定的时间间隔内,Redis 将内存中的全量数据以二进制序列化格式写入磁盘,生成一个紧凑的 .rdb 文件。

3.1.1 触发方式

触发类型 命令/配置 说明
手动保存 SAVE 同步阻塞,由主进程直接执行,期间不处理任何客户端请求
手动后台保存 BGSAVE 异步执行,主进程 fork 子进程,子进程负责写入 RDB 文件
自动触发 save <seconds> <changes> 满足时间与修改次数条件时自动执行 BGSAVE
关闭时保存 shutdown save 正常关闭 Redis 时,若配置了 save 策略则执行一次 RDB 保存

3.1.2 核心流程(BGSAVE)

  1. fork 子进程:主进程调用 fork() 创建子进程,父子进程共享内存页(Copy-on-Write 机制)。
  2. 子进程写入临时 RDB 文件:子进程将内存数据序列化写入磁盘上的临时文件。
  3. 原子替换:子进程完成写入后,使用 rename(2) 系统调用将临时文件原子替换为目标 RDB 文件。
  4. 主进程继续服务:fork 完成后,主进程继续处理客户端请求,不受磁盘 I/O 影响。
Copy-on-Write 关键点:fork 时子进程共享父进程的物理内存页。当父进程需要修改某个内存页时,操作系统会复制该页到新位置,父进程修改副本,子进程仍指向原页。因此 RDB 快照能保证数据一致性,同时内存开销仅在写操作发生时增加。
RDB BGSAVE 核心流程 主进程接收 BGSAVE fork() 创建子进程 子进程写入临时 RDB 原子替换 RDB 文件 主进程继续处理请求 Copy-on-Write 内存共享 fork 后父子进程共享物理内存页。父进程修改数据时,OS 复制被修改的页到新位置, 父进程修改副本,子进程仍指向原页。因此 RDB 快照能保证数据一致性,且内存开销仅在写操作时增加。

3.1.3 优缺点

优势 劣势
文件紧凑,适合全量备份与灾难恢复 无法做到实时持久化,两次快照间数据可能丢失
恢复速度极快,直接加载二进制数据 fork 子进程时可能阻塞主进程(内存越大,fork 耗时越长)
子进程写入不影响主进程性能 大数据集下频繁 BGSAVE 会消耗大量磁盘 I/O 与 CPU

3.2 AOF 日志原理

AOF(Append Only File)持久化以日志形式记录每个写操作命令。Redis 重启时通过回放 AOF 文件中的命令来重建数据集。AOF 提供了更高的数据安全性,支持秒级甚至实时持久化。

3.2.1 写入流程

  1. 命令追加:执行写命令后,将命令以 Redis 协议格式追加到 aof_buf(内存缓冲区)。
  2. 文件写入与同步:根据 appendfsync 策略,将缓冲区内容写入操作系统内核缓冲区,并决定是否调用 fsync() 强制刷盘。
  3. 文件重写:AOF 文件持续增长,通过 BGREWRITEAOF 或自动触发重写,将内存中的当前数据转换为最小命令集,生成新 AOF 文件替换旧文件。

3.2.2 appendfsync 策略对比

策略 行为 数据安全性 性能
always 每次写入都执行 fsync 最高,最多丢失一个命令 最慢,磁盘 I/O 成为瓶颈
everysec 每秒执行一次 fsync 较高,最多丢失 1 秒数据 推荐,兼顾安全与性能
no 由操作系统决定刷盘时机 最低,可能丢失大量数据 最快,依赖 OS 缓存策略
生产建议:绝大多数场景使用 appendfsync everysec。该策略在性能与数据安全之间取得最佳平衡,每秒刷盘一次,即使宕机最多丢失 1 秒内的写操作。

3.2.3 AOF 重写机制

AOF 重写不是对旧 AOF 文件进行整理,而是读取当前内存中的数据状态,生成恢复这些数据所需的最少命令集。例如,对一个 key 执行了 100 次 INCR,重写后只生成一条 SET key 100 命令。

AOF 写入与重写流程 客户端写命令 追加到 aof_buf 写入内核缓冲区 fsync 刷盘 触发重写条件 fork 子进程 读取内存生成最小命令集 原子替换旧 AOF AOF 重写核心 重写基于当前内存数据生成命令,而非分析旧 AOF。例如 100 次 INCR 重写为 1 条 SET,大幅缩减文件体积。

3.3 混合持久化

Redis 4.0 引入了混合持久化模式(aof-use-rdb-preamble yes)。该模式结合了 RDB 的快照速度与 AOF 的日志精度,在 AOF 重写时,将当前内存数据以 RDB 格式写入 AOF 文件头部,后续增量写操作继续以 AOF 格式追加。

3.3.1 文件结构

混合持久化的 AOF 文件由两部分组成:

  • RDB 头部:包含重写时刻的全量数据快照,二进制紧凑格式。
  • AOF 尾部:重写完成后持续追加的增量写命令,文本协议格式。

3.3.2 优势

对比项 纯 RDB 纯 AOF 混合持久化
重启恢复速度 极快 慢(需逐条回放命令) 快(加载 RDB 头部后回放少量 AOF)
数据丢失窗口 较大(两次快照间) 小(取决于 appendfsync) 小(同 AOF)
文件体积 小 大(文本协议) 中等(RDB 头部压缩)
注意:混合持久化仅在 AOF 重写时生成 RDB 头部。如果 Redis 异常崩溃后重启,加载的是最近一次重写生成的混合文件。若重写频率过低,AOF 尾部可能积累大量增量命令,导致恢复速度下降。

3.4 持久化策略选择

选择持久化策略需要权衡数据安全性、性能、恢复速度与运维复杂度。以下给出不同场景的推荐方案。

3.4.1 策略对比总表

策略 配置方式 数据安全 恢复速度 磁盘开销 推荐场景
仅 RDB save 900 1 等 低 极快 低 缓存场景,可接受分钟级数据丢失
仅 AOF(everysec) appendonly yes 高 慢 高 数据重要,需秒级恢复点
RDB + AOF 同时开启两者 最高 快(优先加载 AOF) 高 金融、交易等强一致性场景
混合持久化 aof-use-rdb-preamble yes 高 快 中等 Redis 4.0+ 首选,兼顾安全与性能
关闭持久化 注释所有 save 策略,appendonly no 无 N/A 无 纯内存缓存,数据可丢失(如 Session)

3.4.2 生产环境推荐配置

推荐方案(Redis 4.0+):开启混合持久化,设置 appendfsync everysec,同时保留 RDB 作为备份兜底。
# redis.conf 核心持久化配置
appendonly yes
appendfsync everysec
aof-use-rdb-preamble yes

# RDB 作为辅助备份,频率可降低
save 900 1
save 300 10
save 60 10000

# AOF 重写自动触发
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

3.4.3 避坑指南

  • 不要同时开启 RDB 和 AOF 且关闭混合持久化:重启时 Redis 优先加载 AOF,AOF 文件可能比 RDB 大很多,导致恢复变慢。
  • 避免频繁 fork:RDB 快照和 AOF 重写都会 fork 子进程。如果内存实例很大(如 32GB+),fork 耗时可能达到秒级,导致主进程短暂阻塞。建议将 auto-aof-rewrite-min-size 调大,降低重写频率。
  • 监控磁盘 I/O:AOF 的 always 策略或频繁的 RDB 快照可能导致磁盘 I/O 成为瓶颈。使用 iostat 或 Redis 的 INFO persistence 命令监控持久化状态。
  • RDB 文件损坏:RDB 是二进制格式,一旦损坏可能导致全量数据丢失。建议定期使用 redis-check-rdb 工具检查 RDB 文件完整性。
监控命令:redis-cli INFO persistence 可查看 RDB 上次保存时间、AOF 当前大小、上次重写时间等关键指标,是排查持久化问题的第一入口。