Redis的rdb快照记录时会堵塞吗
Redis 的 RDB(Redis Database)快照持久化机制,根据触发方式的不同,其阻塞行为也有所区别。主要有两种生成 RDB 快照的方式:SAVE 命令和 BGSAVE 命令。
1. SAVE 命令 (阻塞)
SAVE 命令会完全阻塞 Redis 服务器进程。
- 同步执行:当执行
SAVE命令时,Redis 主线程会同步地将所有数据写入 RDB 文件到磁盘。 - 停止服务:在这个过程中,Redis 服务器无法处理任何其他命令请求,包括来自客户端的读写请求。
- 生产环境不建议使用:由于
SAVE命令会长时间阻塞 Redis,特别是在数据量较大时,会导致服务长时间不可用,因此在生产环境中几乎不使用SAVE命令,甚至已经基本被废弃。
2. BGSAVE 命令 (非阻塞,但 fork 阶段有短暂阻塞)
BGSAVE (Background Save) 命令是 Redis 默认和推荐的 RDB 快照方式,它旨在避免阻塞 Redis 主线程。
- 创建子进程:当执行
BGSAVE命令时,Redis 主进程会调用fork()系统调用,创建一个子进程。这个子进程专门负责将数据写入 RDB 文件,而父进程(Redis 主进程)则可以继续处理客户端的请求。 fork()阶段的短暂阻塞:虽然BGSAVE命令本身是后台执行的,但fork()操作会短暂地阻塞 Redis 主进程。fork()操作会复制父进程的页表,这需要一定的时间和内存。- 阻塞时间的长短与 Redis 实例占用的内存大小成正比。例如,每 1GB 内存的
fork操作可能耗时约 20 毫秒。 对于内存较大的实例,fork阻塞时间可能比较明显。 可以通过INFO stats命令查看latest_fork_usec选项来获取最近一次fork操作的耗时(单位是微秒)。
- 写时复制 (Copy-on-Write, COW):
fork()创建子进程后,父子进程会共享相同的内存页面。 只有当父进程(主 Redis 实例)或子进程(RDB 持久化进程)修改共享内存中的某个页面时,操作系统才会复制该页面,从而使得父子进程拥有各自独立的副本。- 这意味着子进程在保存 RDB 文件期间,父进程可以继续接收并处理写命令,而不会影响子进程正在快照的数据一致性。
- COW 机制有效地减少了
fork期间的内存开销,避免了完全复制整个数据集。
- 内存开销:尽管有 COW 机制,但在
BGSAVE期间,由于主进程的写操作会导致页面复制,Redis 的实际内存使用量可能会暂时增加,最高可能达到原有内存的 2 倍(极端情况下)。 如果系统可用内存不足,fork操作可能会失败。