This repository has been archived on 2026-05-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
all-in-kingsoft/hhs/Redis/04-RDB持久化.md
T
2026-05-17 00:06:11 +08:00

7.2 KiB
Raw Blame History

tags, create time
tags create time
Redis
缓存
持久化
RDB
2026-05-15 18:12

RDB 持久化

概述

[!SUMMARY] RDB 是什么? RDB(Redis Database)是 Redis 最早的持久化机制,通过在特定时间点将内存中的数据集写入磁盘形成快照文件(.rdb),实现数据持久化。

核心特点

特性 说明
⚡ 恢复极快 二进制文件直接加载,避免命令回放
📦 文件紧凑 压缩存储,远小于等量 AOF 日志
🔧 架构简单 无额外复杂逻辑,适合备份和迁移
⚠️ 数据窗口丢失 两次快照之间的写操作不可恢复

何时使用

  • 大数据集冷备:定期全量备份到 S3 / OSS
  • 灾难恢复:配合 CI/CD 快速重建实例
  • 大规模数据场景:恢复速度优先于毫秒级数据一致性

[!QUESTION] 为什么 RDB 恢复比 AOF 快? RDB 是直接加载二进制快照到内存,AOF 则需要逐条回放命令——数据量越大差距越明显。

触发机制

手动触发

# 当前线程执行,阻塞主线程 ❌
SAVE

# 主进程 fork 子进程在后台完成(推荐)
BGSAVE

# 查看上次 BGSAVE 状态
LASTSAVE
命令 行为 影响
SAVE 同步保存,主线程阻塞 生产环境禁用!
BGSAVE fork 子进程异步保存 主线程继续服务,但触发 fork 瞬间短暂停顿
BGREWRITEAOF AOF rewrite 与 BGSAVE 可同时运行(不同子进程)

自动触发——条件持久化

通过 redis.conf 配置:

save 900 1     # 900 秒内至少有 1 个 key 被修改 → 触发快照
save 300 10    # 300 秒内至少有 10 个 key 被修改
save 60 10000  # 60 秒内至少有 10000 个 key 被修改

[!QUESTION] 为什么要三档条件?

  • 低活跃度:900s/1key 保证最终一致
  • 中活跃度:300s/10key 平衡频率和数据量
  • 高活跃度:60s/10000key 高频大量变更时快速落盘
# 运行时动态修改
CONFIG SET save "900 1\n300 10\n60 10000"

# 临时关闭自动快照(谨慎!)
CONFIG SET save ""

[!WARNING] CONFIG SET 不持久 CONFIG SET 仅在内存中生效,重启后失效。修改 redis.conf 并 reload 才是持久化的方式。

其他触发场景

场景 说明
shutdown 保存 SHUTDOWN / SHUTDOWN NOSAVE 会在关闭前执行一次完整 RDB 保存(除非显式传 NOSAVE)
AOF rewrite BGREWRITEAOF 重写 AOF 时同样会 fork 子进程生成 RDB preamble(开启混合持久化时)
主从同步 新从节点首次全量同步时,主节点会自动触发 BGSAVE 并将快照传给从节点

[!TIP] 避免频繁触发 多个触发条件同时满足时,Redis 会去重,仅执行一次 BGSAVE。若已有 BGSAVE 在执行,后续的 SAVE 请求将被忽略。

RDB 文件结构

Redis 7.0+ 引入了新格式,更紧凑且支持增量复制:

flowchart TD
    H1["Header"] --> H2["Magic: REDIS"]
    H1 --> H3["RDB Version"]
    H1 --> H4["Reserved / CRC64"]

    D1["DB Number<br/>1 byte"] --> D2["Key Type<br/>1 byte"]
    D2 --> D3["Encoded Key + Value"]

    E1["EOF Marker"] --> E2["CRC64 Checksum<br/>8 bytes"]

    H1 & H2 & H3 & H4 ==> "Dataset Section"
    D1 & D2 & D3 ==> "Dataset Section"
    D3 -.-> "... N keys ..."
    E1 & E2 ==> "Footer"

Fork 过程详解

sequenceDiagram
    participant Server as Redis Server
    participant Parent as 主进程
    child ForkGroup as Forked Child
        participant Child as 写时复制子进程
        participant Disk as 磁盘 (.rdb)
    end

    Server->>Parent: BGSAVE 指令
    Parent->>Server: OK(立即返回)
    Parent->>Child: fork() 创建子进程
    Note over Child: 子进程独享父进程<br/>内存副本(写时复制 COW)
    Child->>Disk: 遍历所有 key → 序列化
    Note over Child: 主进程仍可读写<br/>COW 机制按需拷贝脏页
    Child->>Parent: 生成临时 .rdb.tmp
    Parent->>Disk: RENAME 原子替换
    Parent->>Server: BGSAVE 完成通知

[!WARNING] COW 内存消耗 fork 后主进程若持续写入大值,会导致 COW 副本膨胀。例如你有一个 1GB 的值被频繁修改,fork 后每次写都可能多拷贝一页(4KB)。高峰期建议关闭自动 RDB,仅依赖 AOF。

TTL / 过期键处理

[!QUESTION] RDB 快照会保存已过期的 key 吗? 不会。 Redis 在 fork 子进程前会先执行一次主动过期扫描,清理掉所有已超时的 key。

具体流程:

  1. BGSAVE 触发时,主线程先将当前所有已过期 key 从内存中删除
  2. 子进程 fork 完成后遍历剩余 key → 序列化到 .rdb 文件
  3. 因此:RDB 文件中不会出现已过期键
flowchart LR
    A["BGSAVE 触发"] --> B["主线程: 主动过期<br/>清理超时 Key"]
    B --> C["Fork 子进程"]
    C --> D["子进程: 遍历剩余数据<br/>序列化到 .rdb"]
    D --> E[".rdb 无过期键"]

    style E fill:"#c4e8b0"

[!NOTE] 过期策略差异 虽然 RDB 不保存过期键,但 AOF 可能包含过期命令(如之前的 SET k v EX 100)。AOF 重写时会主动过滤过期键,恢复时也只会加载有效数据。两者优先保证启动时的数据一致性。

恢复流程

# 1. 停止 Redis
redis-cli SHUTDOWN NOSAVE

# 2. 把 .rdb 放到 redis_dir(由 dir 配置决定)
cp dump.rdb /var/lib/redis/

# 3. 启动 Redis
redis-server --daemonize yes

# 4. 验证数据恢复
redis-cli DBSIZE
redis-cli KEYS "*"

RDB vs AOF 对比

维度 RDB AOF
数据安全性 两次快照间数据丢失 每秒/每次可配置,接近零丢失
恢复速度 ⚡ 极快(直接加载二进制文件) 🐢 较慢(需要回放日志)
文件大小 ✅ 小(紧凑压缩) ❌ 大(文本命令日志)
CPU 开销 低(偶尔 fork) 高(持续追加写入)
适用场景 备份、灾难恢复、大数据集冷备 对可用性要求高的在线服务
重启耗时 秒级 取决于日志长度(可 pre-fork)

Redis 7 混合持久化

结合 RDB + AOF 的优点:

aof-use-rdb-preamble yes

开启后,AOF rewrite 不再只追加命令日志,而是先写入一份 RDB 快照,再追加后续命令:

flowchart LR
    T1["传统 AOF 重建<br/>逐条命令回放"] -->|"O(N) 慢"| R1["重建耗时: 长"]

    H1["RDB 二进制快照<br/>全量快速还原"] -->|"秒级加载"| R2["重建耗时: 短"]
    H2["AOF 增量日志<br/>仅保留变更后操作"] -->|"精确到毫秒"| R2

    style R1 fill:"#f9d0c4"
    style R2 fill:"#c4e8b0"

[!TIP] 混合持久化几乎是无脑开启的配置——启动快 + 不丢数据。

运维要点

# 监控 RDB 相关指标
INFO persistence
# rdb_last_bgsave_status: OK
# rdb_last_save_time: 1715000000  ← 最后成功时间戳

# 检查文件大小
ls -lh /var/lib/redis/dump.rdb

# 压缩备份(已内置 LZ4 压缩,通常不需要额外压缩)
tar czf redis-backup.tar.gz dump.rdb

关联笔记