一、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 = 3RDB 保存的是最终状态:
count = 3而不是保存前面的三条命令。
RDB 文件是二进制文件,不能像普通文本文件一样直接阅读。
三、RDB 的触发方式
RDB 可以通过以下几种方式触发:
手动执行
SAVE手动执行
BGSAVE根据配置自动触发
Redis 正常关闭时触发
主从复制过程中触发
其中最重要的是:
SAVE和:
BGSAVE四、SAVE 命令
执行:
SAVERedis 会由主进程直接完成 RDB 文件的生成。
执行过程:
Redis 主进程开始保存 ↓ 停止处理客户端请求 ↓ 把内存数据写入 RDB 文件 ↓ 保存完成后继续处理请求在保存期间,Redis 主线程不能处理其他命令。
所以SAVE会造成 Redis 阻塞。
如果 Redis 中的数据量很大,保存过程可能持续较长时间,客户端会感觉 Redis 卡住。
因此,在生产环境中通常不建议主动使用:
SAVE五、BGSAVE 命令
执行:
BGSAVERedis 会在后台生成 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 FileRDB 和 AOF 的核心区别如下:
| 对比项 | RDB | AOF |
|---|---|---|
| 保存内容 | 某一时刻的数据快照 | Redis 写命令 |
| 持久化方式 | 定期保存 | 持续追加 |
| 默认文件 | dump.rdb | AOF 文件或目录 |
| 文件大小 | 通常较小 | 通常较大 |
| 数据恢复 | 通常较快 | 通常相对较慢 |
| 数据安全性 | 可能丢失两次快照间的数据 | 通常丢失更少 |
| 适用场景 | 备份、快速恢复 | 更高的数据安全要求 |
可以这样理解:
RDB:定期拍照例如:
10:00 拍一次 10:05 拍一次 10:10 拍一次而 AOF 类似于记录每一次操作:
SET count 1 INCR count DEL codeRedis 恢复时,可以重新执行这些写命令。
十九、常用 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 对比
| 对比项 | SAVE | BGSAVE |
|---|---|---|
| 执行进程 | Redis 主进程 | 子进程 |
| 是否阻塞 | 整个保存过程都会阻塞 | fork 时短暂阻塞 |
| 是否处理客户端请求 | 保存期间不能处理 | 父进程可以继续处理 |
| 适用场景 | 测试或特殊情况 | 实际生产环境 |
| 推荐程度 | 一般不推荐 | 更常用 |
二十二、核心流程总结
BGSAVE的完整过程:
客户端执行 BGSAVE ↓ Redis 主进程执行 fork() ↓ 创建 RDB 子进程 ↓ 父子进程共享物理内存 ↓ 父进程继续处理客户端请求 ↓ 子进程读取旧数据生成 RDB ↓ 父进程写数据时触发写时复制 ↓ 父进程使用新页,子进程使用旧页 ↓ 子进程先生成临时 RDB 文件 ↓ 成功后替换旧的 dump.rdb ↓ 子进程退出 ↓ 无人使用的旧内存页被回收二十三、重点结论
RDB 是 Redis 的快照持久化方式。
RDB 保存的是某一时刻的数据状态,不是每一条 Redis 命令。
默认 RDB 文件通常是:
dump.rdbSAVE由主进程保存,会阻塞 Redis。BGSAVE通过fork()创建子进程,由子进程生成 RDB。fork()后不会立即复制整个 Redis 内存。父子进程读数据时,共享同一批物理内存页。
父进程写数据时,操作系统复制被修改的内存页。
父进程使用新页,子进程继续使用旧页。
子进程保存结束后直接退出,不需要合并或覆盖数据。
没有被修改的内存页仍然保持共享。
BGSAVE期间写操作越多,额外内存消耗越大。RDB 文件较小,恢复速度快,适合备份。
RDB 可能丢失两次快照之间的数据。
对数据安全要求较高时,通常需要结合 AOF 或其他持久化方案。
一句话概括:
RDB 是 Redis 定期生成的内存数据快照;BGSAVE 通过子进程生成快照,父子进程读时共享内存,父进程写时复制被修改的内存页,保存完成后无需合并数据。