--- tags: [redis, rdb-aof, persistence, fork, snapshot] create time: 2026-08-08 18:43 update time: 2026-08-08 18:43 --- # RDB 与 AOF 持久化 ## 概述 Redis 作为内存数据库,崩溃重启后需要可靠的数据恢复机制。RDB(快照)和 AOF(追加日志)是 Redis 提供的两种持久化方案,各有优劣。Redis 4.0 之后又引入了混合持久化(Hybrid Persistence),结合了两者之长。理解它们的机制和取舍,是在生产环境选型的基础。 ## 核心原理 ### RDB — 快照机制 RDB(Redis Database)在指定时间间隔内将内存中的数据集写入磁盘,生成一个压缩的二进制文件(dump.rdb)。 **fork 子进程快照流程:** ```mermaid 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 ` 配置自动触发(如 `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 增量日志: ```mermaid graph LR A[BGSTART] --> B[fork 子进程] B --> C["写 RDB 部分
(全部内存快照)"] B --> D["父进程收集
AOF 增量命令"] C --> E["合并为临时文件"] D --> E E --> F["原子替换 AOF 文件"] ``` 优势: - 启动速度远快于纯 AOF(RDB 部分只需加载一次全量快照) - 数据安全性接近 pure AOF everysec(RDB 部分保证了到 fork 时刻的完整状态) ### 选型对比 | 维度 | RDB | AOF(everysec) | 混合持久化 | |------|-----|----------------|----------| | 数据丢失风险 | 高(丢最近快照期间的数据) | 低(最多丢 1s) | 极低 | | 启动恢复速度 | 快(单个文件) | 慢(逐条重放) | 较快 | | 磁盘占用 | 小(压缩二进制) | 大(文本指令) | 中等 | | CPU 开销 | 高(定期全量拷贝) | 低(持续追加) | 中 | | 适用场景 | 容灾备份、可接受短暂丢数据 | 对数据一致性要求高 | 兼顾速度与安全的推荐方案 | ## 代码示例 Go 中使用 Redigo 触发和管理持久化: ```go 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" ``` ```bash # 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 过大的内存开销。 ## 关联笔记 - [[03.Redis/core/Redis 五大核心数据结构]] - [[03.Redis/core/集群与哨兵机制]] - [[03.Redis/strategies/多级缓存架构设计]]