Redis RDB 持久化笔记

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 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 主进程执行 forkRedis 收到BGSAVE命令后主进程调用操作系统的fork()创建一个子进程。父进程继续提供 Redis 服务 子进程负责生成 RDB 文件2. 父子进程共享内存刚刚执行完fork()时并不会立即复制整个 Redis 内存。父进程和子进程会暂时共享相同的物理内存页。父进程 ─┐ ├── 共享原来的物理内存 子进程 ─┘这种机制与操作系统的Copy-On-Write有关中文叫写时复制七、写时复制 Copy-On-Write1. 父子进程都执行读操作如果父进程和子进程都只是读取数据那么它们会继续共享原来的物理内存。父进程读数据不复制 子进程读数据不复制因为读取操作不会改变数据所以没有必要复制内存。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十一、自动触发 RDBRedis 可以在配置文件中设置自动保存规则。例如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 的核心区别如下对比项RDBAOF保存内容某一时刻的数据快照Redis 写命令持久化方式定期保存持续追加默认文件dump.rdbAOF 文件或目录文件大小通常较小通常较大数据恢复通常较快通常相对较慢数据安全性可能丢失两次快照间的数据通常丢失更少适用场景备份、快速恢复更高的数据安全要求可以这样理解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需要根据业务的数据安全要求和备份策略决定。即使开启了 AOFRDB 仍然可以用于定期备份 快速恢复 灾难恢复 主从复制二十一、SAVE 和 BGSAVE 对比对比项SAVEBGSAVE执行进程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 通过子进程生成快照父子进程读时共享内存父进程写时复制被修改的内存页保存完成后无需合并数据。