Files

5.8 KiB
Raw Permalink Blame History

tags, create time, update time
tags create time update time
redis
rdb-aof
persistence
fork
snapshot
2026-08-08 18:43 2026-08-08 18:43

RDB 与 AOF 持久化

概述

Redis 作为内存数据库,崩溃重启后需要可靠的数据恢复机制。RDB(快照)和 AOF(追加日志)是 Redis 提供的两种持久化方案,各有优劣。Redis 4.0 之后又引入了混合持久化(Hybrid Persistence),结合了两者之长。理解它们的机制和取舍,是在生产环境选型的基础。

核心原理

RDB — 快照机制

RDB(Redis Database)在指定时间间隔内将内存中的数据集写入磁盘,生成一个压缩的二进制文件(dump.rdb)。

fork 子进程快照流程:

sequenceDiagram
    participant Client as 客户端
    participant Master as Redis主进程
    participant Child as fork子进程
    participant Disk as 磁盘

    Client->>Master: SAVE / BGSAVE
    Master->>Master: 执行 bgsave
    Master->>Master: fork 创建子进程
    Note over Master: 父进程继续处理请求
    Master->>Child: 子进程独占写内存
    Child->>Child: 遍历内存数据结构
    Child->>Child: 写入临时 RDB 文件
    Child->>Disk: mv 替换 dump.rdb
    Child-->>Master: SIGCHLD 通知完成

关键细节:

  • COW(Copy-On-Write):fork 时父子进程共享内存页,子进程读数据,父进程写数据。当某页被修改时操作系统复制该页给子进程使用。这意味着 RDB 过程中内存峰值 = 当前内存 + fork 瞬间的增量变化量。
  • save vs bgsave:SAVE 阻塞所有客户端等待完成(生产环境禁用);BGSAVE 后台异步执行。
  • 自动触发:通过 save <seconds> <changes> 配置自动触发(如 save 900 1 表示 900 秒内有至少 1 个 key 被修改则触发)。
  • RDB 压缩:RDB 文件本身是无损压缩的二进制格式,不同版本间不兼容(不能跨版本还原)。

Warning

RDB 每次全量快照,两次快照之间的数据在崩溃时会丢失。不适合对数据完整性要求极高的场景。

AOF — 追加日志

AOF(Append Only File)以日志形式记录每个写操作,重启时重放日志恢复数据。

appendfsync 三种策略:

策略 fsync 频率 性能 数据安全性
always 每条命令一次 最差(约等于MySQL innodb_flush_log_at_trx_commit=1) 最高,零丢失
everysec(默认) 每秒一次 良好(1ms 系统调用) 丢 1 秒数据
no OS 决定 最佳 完全取决于 OS 刷新节奏

AOF 重写(Rewrite)原理:

AOF 文件会随时间越来越大。重写不是简单地删除旧文件再写新内容,而是:

  1. 父进程 fork 子进程
  2. 子进程遍历内存数据,将每个 key 用 SET key value 命令序列化(而非读取旧 AOF)
  3. 父进程同时将新写命令写入 aof_rewrite_buffer
  4. 子进程完成后将新数据和缓冲区合并写入临时文件
  5. 原子替换原 AOF 文件

Note

AOF 重写期间,旧 AOF 保持不变直到新文件准备好,保证不会丢失任何已确认的数据。重写后的 AOF 可能比原来的小很多(去除了已过期 key 的旧记录)。

混合持久化

Redis 4.0+ 引入的混合持久化 = RDB 全量快照 + AOF 增量日志:

graph LR
    A[BGSTART] --> B[fork 子进程]
    B --> C["写 RDB 部分<br/>(全部内存快照)"]
    B --> D["父进程收集<br/>AOF 增量命令"]
    C --> E["合并为临时文件"]
    D --> E
    E --> F["原子替换 AOF 文件"]

优势:

  • 启动速度远快于纯 AOF(RDB 部分只需加载一次全量快照)
  • 数据安全性接近 pure AOF everysec(RDB 部分保证了到 fork 时刻的完整状态)

选型对比

维度 RDB AOF(everysec) 混合持久化
数据丢失风险 高(丢最近快照期间的数据) 低(最多丢 1s) 极低
启动恢复速度 快(单个文件) 慢(逐条重放) 较快
磁盘占用 小(压缩二进制) 大(文本指令) 中等
CPU 开销 高(定期全量拷贝) 低(持续追加) 中
适用场景 容灾备份、可接受短暂丢数据 对数据一致性要求高 兼顾速度与安全的推荐方案

代码示例

Go 中使用 Redigo 触发和管理持久化:

conn, _ := redis.Dial("tcp", "localhost:6379")
defer conn.Close()

// 手动触发 BGSAVE(生产环境通常交给监控定时触发)
res, _ := redis.String(conn.Do("BGSAVE"))
// res == "Background saving started"

// 查看上次 BGSAVE 的状态
info, _ := redis.StringMap(conn.Do("INFO", "persistent"))
fmt.Println(info["last_bgsave_status"]) // "ok" or "err"
# Redis CLI 检查 AOF 状态
127.0.0.1:6379> CONFIG GET appendonly
1) "appendonly"
2) "yes"            # yes=开启, no=关闭

# 动态开启 AOF 重写
127.0.0.1:6379> CONFIG SET auto-aof-rewrite-percentage 100
OK

实践场景

  1. 默认推荐:开启混合持久化(aof-use-rdb-preamble yes),既保证数据安全又控制启动时间。大多数互联网公司的标准配置。

  2. 冷备策略:每天凌晨做一次 SAVE(或 BGSAVE),将 dump.rdb 上传到 OSS/S3。注意 SAVE 是阻塞命令,不要在高峰期执行。

  3. 迁移场景:从一个 Redis 集群迁到另一个,用 BGSAVE 拿到最新快照后复制文件到新实例,恢复速度远超 AOF 重放。

  4. 大数据量陷阱:当内存超过 10GB 时,fork 导致 COW 成本剧增。考虑增大 AOF 重写阈值或将业务拆分到多实例,避免单次 fork 过大的内存开销。

关联笔记