RDB做后台持久化(bgsave)时,如果主线程还在持续写入大量新数据,这些新数据会被保存进当前的RDB文件吗
直接回答:
不会。 这些在新数据(或对老数据的修改)不会被保存进当前正在生成的 RDB 文件中。
为什么不会?(原理解析)
这与 Redis 执行 bgsave 时的底层机制——操作系统的 fork() 系统调用 和 写时复制(Copy-On-Write, COW) 技术密切相关。
具体过程如下:
瞬间快照(Point-in-Time Snapshot):
当 Redis 主线程收到bgsave命令时,它会调用操作系统的fork()函数创建一个子进程。在这个fork()完成的那一微秒,子进程就获得了父进程(主线程)当前内存数据的一个“虚拟快照”。当前 RDB 文件只会保存这个时间点的数据。写时复制(Copy-On-Write):
fork()之后,父子进程共享同一块物理内存。子进程开始默默地遍历这块内存,把数据写入磁盘上的临时 RDB 文件中。
此时,如果主线程(父进程)接收到了新的写入请求:- 如果是新增数据:主线程会申请新的内存空间来存放这些数据,子进程根本看不到这块新内存。
- 如果是修改已有数据:操作系统会触发“写时复制”机制。操作系统会把要修改的那个内存页(通常是 4KB)复制一份出来给主线程去修改。而子进程继续读取原来那份旧的、未被修改的内存页。
结论: 子进程在整个持久化过程中,看到的数据永远是 fork() 发生那一瞬间的静止画面。因此,主线程后续写入的大量新数据,绝对不会进入当前的 RDB 文件。
这些新数据去了哪里?安全吗?
- 存在内存中: 这些新数据依然安全地存在于 Redis 的内存中,可以被客户端正常查询和访问。
- 下一次 RDB: 它们会被包含在下一次执行
bgsave时生成的 RDB 文件中。 - 如果开启了 AOF: 如果你的 Redis 同时开启了 AOF(Append Only File),这些新数据的写操作会被记录到 AOF 缓冲区,并根据你的刷盘策略(如
everysec)追加到 AOF 文件中,所以不用担心数据丢失。
⚠️ 延伸警告:bgsave 期间持续大量写入带来的隐患
虽然新数据不会影响当前的 RDB 文件,但在 bgsave 期间持续大量写入会带来严重的性能和稳定性风险:
内存暴涨(OOM 风险):
由于“写时复制”机制,主线程修改的数据越多,操作系统需要复制的内存页就越多。如果你的 Redis 占用了 10GB 内存,在bgsave期间你修改了其中 5GB 的数据,那么 Redis 实际占用的物理内存会飙升到 15GB。如果服务器物理内存不足,可能会导致 Redis 崩溃(OOM 被系统杀死)或引发严重的 Swap(使用虚拟内存),导致 Redis 性能出现断崖式下跌。Fork 阻塞:
虽然bgsave是异步的,但主线程在执行fork()操作时是阻塞的。如果 Redis 内存非常大,复制内存页表(Page Table)也需要一定时间。在此期间,主线程无法处理任何客户端请求。
总结: RDB 是一种“时间点快照”。bgsave 开始后的所有新写入都不会进入当前快照,但开发者需要警惕大量写入引发的“写时复制”内存膨胀问题。