Redis RDB 持久化笔记

一、RDB 是什么

RDB,全称是:

Redis Database Backup

它是 Redis 提供的一种持久化方式。

Redis 的数据主要保存在内存中,如果 Redis 进程退出、服务器宕机或断电,内存中的数据就会消失。

RDB 可以在某一个时间点,把 Redis 内存中的数据保存到磁盘,生成一个二进制快照文件。

默认文件名通常是:

dump.rdb

可以把 RDB 理解为:

给 Redis 当前的内存数据拍一张照片。

例如,某一时刻 Redis 中有:

SET username user1 SET age 20 SADD users 1 2 3

执行 RDB 持久化后,这些数据会被保存到dump.rdb文件中。

Redis 重启时,可以读取这个文件,把数据重新加载到内存中。


二、RDB 保存的是什么

RDB 保存的是:

Redis 在某一个时间点的数据状态。

它不是保存每一条执行过的 Redis 命令,而是直接保存最终的数据结果。

例如:

SET count 1 INCR count INCR count

最终:

count = 3

RDB 保存的是最终状态:

count = 3

而不是保存前面的三条命令。

RDB 文件是二进制文件,不能像普通文本文件一样直接阅读。


三、RDB 的触发方式

RDB 可以通过以下几种方式触发:

  1. 手动执行SAVE

  2. 手动执行BGSAVE

  3. 根据配置自动触发

  4. Redis 正常关闭时触发

  5. 主从复制过程中触发

其中最重要的是:

SAVE

和:

BGSAVE

四、SAVE 命令

执行:

SAVE

Redis 会由主进程直接完成 RDB 文件的生成。

执行过程:

Redis 主进程开始保存 ↓ 停止处理客户端请求 ↓ 把内存数据写入 RDB 文件 ↓ 保存完成后继续处理请求

在保存期间,Redis 主线程不能处理其他命令。

所以SAVE会造成 Redis 阻塞。

如果 Redis 中的数据量很大,保存过程可能持续较长时间,客户端会感觉 Redis 卡住。

因此,在生产环境中通常不建议主动使用:

SAVE

五、BGSAVE 命令

执行:

BGSAVE

Redis 会在后台生成 RDB 文件。

基本流程:

Redis 主进程 ↓ fork() 创建子进程 ↓ 子进程负责生成 RDB ↓ 父进程继续处理客户端请求

父进程和子进程的任务分别是:

父进程:继续处理客户端请求 子进程:读取内存数据并生成 RDB 文件

因此,BGSAVE不会像SAVE一样,在整个磁盘写入期间阻塞主进程。

生产环境中通常优先使用:

BGSAVE

不过要注意:

BGSAVE不是完全没有阻塞。

创建子进程时需要执行fork(),这个过程仍然会造成 Redis 主进程短暂阻塞。

Redis 数据量越大,fork()过程通常越耗时。


六、BGSAVE 的完整执行过程

1. Redis 主进程执行 fork

Redis 收到BGSAVE命令后,主进程调用操作系统的:

fork()

创建一个子进程。

父进程:继续提供 Redis 服务 子进程:负责生成 RDB 文件

2. 父子进程共享内存

刚刚执行完fork()时,并不会立即复制整个 Redis 内存。

父进程和子进程会暂时共享相同的物理内存页。

父进程 ─┐ ├── 共享原来的物理内存 子进程 ─┘

这种机制与操作系统的:

Copy-On-Write

有关,中文叫:

写时复制

七、写时复制 Copy-On-Write

1. 父子进程都执行读操作

如果父进程和子进程都只是读取数据,那么它们会继续共享原来的物理内存。

父进程读数据:不复制 子进程读数据:不复制

因为读取操作不会改变数据,所以没有必要复制内存。


2. 父进程执行写操作

BGSAVE期间,父进程仍然需要处理客户端请求。

示意图:

假设原来的数据为:

count = 10

此时执行:

SET count 20

父进程需要修改共享内存中的数据。

为了防止影响子进程正在生成的快照,操作系统会复制被修改的内存页。

复制后:

子进程读取旧内存页:count = 10 父进程使用新内存页:count = 20

所以:

RDB 文件中保存的是:count = 10 Redis 当前对外提供的是:count = 20

这就保证了子进程可以获得一个相对稳定的旧数据快照,同时父进程也可以继续接收新的写请求。


3. 不是复制整个 Redis 内存

写时复制不是每次写操作都复制整个 Redis 数据。

通常是按照操作系统的内存页进行复制。

也就是:

父进程修改哪个内存页 ↓ 操作系统复制哪个内存页

没有被修改的内存页仍然由父子进程共享。

因此:

写操作少 → 复制的内存页少 → 额外内存消耗较小
写操作多 → 复制的内存页多 → 额外内存消耗较大

八、子进程完成保存后会发生什么

子进程完成 RDB 文件生成后,会直接退出。

子进程完成 RDB ↓ 子进程退出 ↓ 不再使用的旧内存页被操作系统回收

父进程继续使用自己当前的内存页。

需要特别注意:

父进程不会把复制出来的数据重新覆盖回原来的内存。

原因是:

写时复制发生后,新内存页已经直接成为父进程正式使用的内存。

操作系统会修改父进程的内存映射,使父进程指向新的内存页。

因此最后不需要:

数据合并 数据覆盖 数据同步

正确理解是:

开始时:父子共享旧页 父进程写数据:复制一个新页 父进程:使用新页 子进程:继续使用旧页 子进程结束:旧页无人使用后被回收

九、BGSAVE 示例

假设执行BGSAVE前,Redis 中有:

stock = 100

执行:

BGSAVE

刚开始时:

父进程 ─┐ ├── 共享内存:stock = 100 子进程 ─┘

此时客户端执行:

DECR stock

父进程需要写数据,因此发生写时复制。

子进程看到:stock = 100 父进程看到:stock = 99

最终:

RDB 文件中:stock = 100 Redis 当前内存中:stock = 99

子进程完成保存后:

子进程退出 父进程继续使用 stock = 99

不会把stock = 99再覆盖到某个旧内存中。


十、RDB 文件如何生成

子进程生成 RDB 时,一般不会直接覆盖原来的dump.rdb

通常流程是:

先生成临时 RDB 文件 ↓ 临时文件写入成功 ↓ 使用新文件替换旧的 dump.rdb

这样做的好处是:

如果生成过程中发生异常,不会直接破坏原来可用的 RDB 文件。

例如:

旧文件:dump.rdb 新文件:临时文件 新文件保存成功后: 临时文件替换 dump.rdb

十一、自动触发 RDB

Redis 可以在配置文件中设置自动保存规则。

例如:

save 900 1 save 300 10 save 60 10000

含义分别是:

save 900 1

表示:

900 秒内,如果至少有 1 个 key 被修改,就执行一次 RDB 快照。

save 300 10

表示:

300 秒内,如果至少有 10 个 key 被修改,就执行一次 RDB 快照。

save 60 10000

表示:

60 秒内,如果至少有 10000 个 key 被修改,就执行一次 RDB 快照。

这些条件是:

满足任意一个条件,就可以触发 RDB。

不是要求三个条件同时满足。


哪些操作算修改

会改变 Redis 数据的命令通常会被计入修改次数,例如:

SET DEL INCR DECR HSET LPUSH SADD ZADD

只读操作不会被计入:

GET HGET LRANGE SMEMBERS ZRANGE

十二、RDB 文件的位置

RDB 文件名通常由以下配置决定:

dbfilename dump.rdb

保存目录由以下配置决定:

dir /var/lib/redis

组合起来,文件路径可能是:

/var/lib/redis/dump.rdb

可以通过 Redis 命令查看:

CONFIG GET dbfilename

查看文件名。

CONFIG GET dir

查看保存目录。


十三、Redis 如何使用 RDB 恢复数据

Redis 启动时,会检查配置目录中是否存在 RDB 文件。

基本恢复过程:

Redis 启动 ↓ 找到 dump.rdb ↓ 读取 RDB 文件 ↓ 把数据加载到内存 ↓ 开始处理客户端请求

因此,只要 RDB 文件存在并且没有损坏,Redis 就可以恢复快照中的数据。


十四、RDB 为什么可能丢失数据

RDB 保存的是某一时刻的数据快照,不会实时保存每一次数据修改。

例如:

10:00 执行一次 RDB 10:01 写入数据 A 10:02 写入数据 B 10:03 Redis 宕机

Redis 重启时,只能恢复 10:00 的快照。

因此:

10:00 之前的数据:可以恢复 10:01 到 10:03 的数据:可能丢失

所以 RDB 的数据安全性取决于快照执行频率。

快照间隔越长,宕机时可能丢失的数据越多。


十五、BGSAVE 对内存的影响

执行BGSAVE时,父子进程刚开始共享物理内存,所以不会立刻复制完整的 Redis 数据。

但是在保存期间,如果发生大量写操作,会不断触发写时复制。

例如 Redis 本身占用:

4 GB

如果BGSAVE期间修改了大量数据,就可能额外复制大量内存页。

因此,实际内存占用可能明显上升。

需要关注:

Redis 当前使用内存 服务器剩余内存 BGSAVE 期间的写入量 是否可能发生内存不足

极端情况下,如果内存不足,可能导致:

fork 失败 子进程创建失败 RDB 保存失败 操作系统触发 OOM

十六、RDB 的优点

1. 文件紧凑

RDB 是经过编码的二进制快照文件,通常比较紧凑。

适合:

数据备份 远程传输 定期归档 灾难恢复

2. 恢复速度较快

RDB 保存的是完整的数据状态。

Redis 启动时只需要直接加载数据,不需要重新执行大量写命令。

因此,大数据量情况下,RDB 的恢复速度通常较快。


3. 对主进程影响相对较小

使用BGSAVE时,磁盘写入由子进程负责。

父进程仍然可以继续处理客户端请求。


4. 适合做定期备份

可以定期保存不同时间点的 RDB 文件,例如:

dump-2026-07-01.rdb dump-2026-07-02.rdb dump-2026-07-03.rdb

发生问题时,可以选择恢复某一个历史版本。


十七、RDB 的缺点

1. 可能丢失最近的数据

RDB 不是实时持久化。

两次快照之间发生宕机,期间的数据可能丢失。

这是 RDB 最主要的问题。


2. fork 会造成短暂阻塞

虽然子进程负责写磁盘,但是创建子进程的fork()操作仍然由主进程完成。

Redis 数据越大,fork()可能越慢。


3. 写时复制会增加内存压力

BGSAVE期间写操作越多,复制的内存页就越多。

可能导致服务器内存使用量明显增加。


4. 不适合单独用于高数据安全场景

例如:

支付记录 余额变化 关键订单 重要交易数据

如果只依赖 RDB,可能无法接受几分钟数据丢失的风险。

这种场景通常还需要结合:

AOF 数据库 消息队列 其他持久化方案

十八、RDB 和 AOF 的区别

Redis 还有另一种持久化方式:

AOF

全称是:

Append Only File

RDB 和 AOF 的核心区别如下:

对比项RDBAOF
保存内容某一时刻的数据快照Redis 写命令
持久化方式定期保存持续追加
默认文件dump.rdbAOF 文件或目录
文件大小通常较小通常较大
数据恢复通常较快通常相对较慢
数据安全性可能丢失两次快照间的数据通常丢失更少
适用场景备份、快速恢复更高的数据安全要求

可以这样理解:

RDB:定期拍照

例如:

10:00 拍一次 10:05 拍一次 10:10 拍一次

而 AOF 类似于记录每一次操作:

SET count 1 INCR count DEL code

Redis 恢复时,可以重新执行这些写命令。


十九、常用 RDB 命令

1. 同步保存

SAVE

特点:

由主进程执行 会阻塞 Redis 生产环境通常不建议随意使用

2. 后台保存

BGSAVE

特点:

创建子进程 子进程生成 RDB 父进程继续处理请求

3. 查看最后一次成功保存时间

LASTSAVE

返回最后一次成功生成 RDB 的 Unix 时间戳。


4. 查看持久化状态

INFO persistence

常见字段包括:

rdb_bgsave_in_progress

表示当前是否正在执行BGSAVE

rdb_last_save_time

表示最后一次成功保存时间。

rdb_last_bgsave_status

表示上一次BGSAVE是否成功。

rdb_changes_since_last_save

表示从上一次保存后,发生了多少次数据修改。


二十、关闭自动 RDB

如果想关闭自动快照,可以配置:

save ""

表示不再根据自动保存规则触发 RDB。

但通常仍然可以手动执行:

BGSAVE

是否关闭 RDB,需要根据业务的数据安全要求和备份策略决定。

即使开启了 AOF,RDB 仍然可以用于:

定期备份 快速恢复 灾难恢复 主从复制

二十一、SAVE 和 BGSAVE 对比

对比项SAVEBGSAVE
执行进程Redis 主进程子进程
是否阻塞整个保存过程都会阻塞fork 时短暂阻塞
是否处理客户端请求保存期间不能处理父进程可以继续处理
适用场景测试或特殊情况实际生产环境
推荐程度一般不推荐更常用

二十二、核心流程总结

BGSAVE的完整过程:

客户端执行 BGSAVE ↓ Redis 主进程执行 fork() ↓ 创建 RDB 子进程 ↓ 父子进程共享物理内存 ↓ 父进程继续处理客户端请求 ↓ 子进程读取旧数据生成 RDB ↓ 父进程写数据时触发写时复制 ↓ 父进程使用新页,子进程使用旧页 ↓ 子进程先生成临时 RDB 文件 ↓ 成功后替换旧的 dump.rdb ↓ 子进程退出 ↓ 无人使用的旧内存页被回收

二十三、重点结论

  1. RDB 是 Redis 的快照持久化方式。

  2. RDB 保存的是某一时刻的数据状态,不是每一条 Redis 命令。

  3. 默认 RDB 文件通常是:

dump.rdb
  1. SAVE由主进程保存,会阻塞 Redis。

  2. BGSAVE通过fork()创建子进程,由子进程生成 RDB。

  3. fork()后不会立即复制整个 Redis 内存。

  4. 父子进程读数据时,共享同一批物理内存页。

  5. 父进程写数据时,操作系统复制被修改的内存页。

  6. 父进程使用新页,子进程继续使用旧页。

  7. 子进程保存结束后直接退出,不需要合并或覆盖数据。

  8. 没有被修改的内存页仍然保持共享。

  9. BGSAVE期间写操作越多,额外内存消耗越大。

  10. RDB 文件较小,恢复速度快,适合备份。

  11. RDB 可能丢失两次快照之间的数据。

  12. 对数据安全要求较高时,通常需要结合 AOF 或其他持久化方案。

一句话概括:

RDB 是 Redis 定期生成的内存数据快照;BGSAVE 通过子进程生成快照,父子进程读时共享内存,父进程写时复制被修改的内存页,保存完成后无需合并数据。