5.8 KiB
tags, create time, update time
| tags | create time | update time | |||||
|---|---|---|---|---|---|---|---|
|
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 文件会随时间越来越大。重写不是简单地删除旧文件再写新内容,而是:
- 父进程 fork 子进程
- 子进程遍历内存数据,将每个 key 用
SET key value命令序列化(而非读取旧 AOF) - 父进程同时将新写命令写入
aof_rewrite_buffer - 子进程完成后将新数据和缓冲区合并写入临时文件
- 原子替换原 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
实践场景
-
默认推荐:开启混合持久化(
aof-use-rdb-preamble yes),既保证数据安全又控制启动时间。大多数互联网公司的标准配置。 -
冷备策略:每天凌晨做一次
SAVE(或BGSAVE),将 dump.rdb 上传到 OSS/S3。注意SAVE是阻塞命令,不要在高峰期执行。 -
迁移场景:从一个 Redis 集群迁到另一个,用
BGSAVE拿到最新快照后复制文件到新实例,恢复速度远超 AOF 重放。 -
大数据量陷阱:当内存超过 10GB 时,fork 导致 COW 成本剧增。考虑增大 AOF 重写阈值或将业务拆分到多实例,避免单次 fork 过大的内存开销。