当前位置:首页 > 问答 > 正文

Redis里RDB转储到底是咋回事,里面那些细节和机制其实挺复杂的,想弄明白得慢慢拆解讲讲

为什么要“拍照”?——RDB的用途

首先得明白,Redis的数据是放在内存里的,内存速度快,但有个致命缺点:一断电,里面的数据就全没了,为了数据安全,必须得有个办法把内存里的数据持久化到不会丢失的硬盘上,RDB就是Redis提供的两种持久化方式中的一种(另一种叫AOF)。

它的主要用处有两个:

  1. 灾难恢复:如果Redis服务器突然宕机了,重启之后可以通过加载最近的RDB文件,快速地将数据恢复到拍快照时的状态。
  2. 方便迁移:因为RDB文件是一个紧凑的二进制文件,你可以很容易地把这个文件拷贝到另一台服务器上,相当于复制了一份完整的数据副本,用于备份、测试或者扩展。

谁来决定“拍照”?——触发RDB的时机

Redis里RDB转储到底是咋回事,里面那些细节和机制其实挺复杂的,想弄明白得慢慢拆解讲讲

Redis不会无时无刻地拍照,那样太耗费资源了,那它什么时候会拍这张快照呢?主要有两种方式:

  1. 自动触发(根据配置规则):这是最常见的方式,你可以在Redis的配置文件(redis.conf)里设置一些规则,在900秒(15分钟)内,如果至少有1个键被修改了”或者“在300秒(5分钟)内,如果至少有10个键被修改了”,只要满足其中任意一条条件,Redis就会自动启动一次RDB快照过程,你可以设置多条规则,以适应不同强度的写入场景。
  2. 手动触发
    • Save命令:执行SAVE命令后,Redis会立即开始拍快照,但在快照完成之前,整个服务器会处于阻塞状态,无法处理任何其他的命令,这在生产环境中基本不会用。
    • BGSave命令:执行BGSAVE命令(Background Save),这个命令是关键,Redis会fork出一个子进程,然后由这个子进程去负责创建RDB文件,而主进程继续正常提供服务,处理客户端的请求,这才是推荐使用的方式。

拍照时会不会“卡住”?——BGSave的核心机制:fork和写时复制

这里就到了最核心、最需要弄明白的地方了,前面说BGSAVE命令不会阻塞主进程,它是怎么做到的呢?秘诀就在于操作系统的fork() 系统调用和写时复制(Copy-on-Write,简称COW) 机制。

Redis里RDB转储到底是咋回事,里面那些细节和机制其实挺复杂的,想弄明白得慢慢拆解讲讲

  1. fork出子进程:当主进程收到BGSAVE命令后,它会调用fork(),这个操作会创建出一个和主进程几乎一模一样的子进程,注意,在刚fork完的那一刻,子进程拥有和主进程完全相同的内存数据副本的指针,也就是说,它能看到主进程内存里所有的键值对。
  2. 写时复制(COW)的魔法:关键点来了!虽然子进程有了数据的“视图”,但它并不是真的把几个G的内存数据全部复制一遍,那样的话跟阻塞也没什么区别了,操作系统使用了“写时复制”技术,这意味着,在fork之后,主进程和子进程共享同一份物理内存页
    • 只有当主进程需要修改某个数据时(比如客户端发来了一个SET命令),操作系统才会将被修改的那一页内存数据复制一份副本,然后主进程在这个新副本上进行修改。
    • 而对于子进程来说,它看到的内存数据始终是fork那一瞬间的样子(即未被修改的原始页),这样一来,子进程就能安心地遍历这个静止的数据快照,并将其写入RDB文件,而完全不用关心主进程后续又在修改什么。

这个过程非常巧妙,它保证了快照的一致性是某个精确时间点的数据状态),也保证了高性能(除非有大量写入,否则子进程的工作对主进程影响很小)。

照片是怎么“洗”出来的?——RDB文件的生成与格式

子进程在干嘛呢?它独自安静地遍历当前数据库的所有键值对,并按照特定的格式把它们写入一个临时的RDB文件,等把所有数据都写完后,再用这个临时文件原子性地替换掉旧的RDB文件(如果存在的话),这样做是为了保证RDB文件的完整性,避免在写入一半时发生故障导致文件损坏。

Redis里RDB转储到底是咋回事,里面那些细节和机制其实挺复杂的,想弄明白得慢慢拆解讲讲

RDB文件本身是二进制的,经过压缩,所以体积相对较小,它的内容大致包括:文件头(标识这是RDB文件、Redis版本号等)、数据库数据(键值对及其过期时间等)、文件尾的校验和等。

这张“照片”的优缺点

  • 优点

    • 适合备份:RDB文件是一个单一的紧凑文件,很容易被压缩和传输,非常适合做定时备份和灾难恢复。
    • 最大化性能:父进程在保存RDB文件时唯一要做的就是fork一个子进程,之后所有工作由子进程完成,父进程不需要进行任何磁盘I/O操作。
    • 快速重启:相比于另一种AOF方式,用RDB文件来恢复大数据集的速度更快。
  • 缺点

    • 可能丢失数据:RDB是定时拍的快照,如果Redis意外宕机,从上一次拍快照到宕机之间的数据修改就会丢失,对于数据可靠性要求非常高的场景,这可能无法接受。
    • fork可能阻塞:虽然子进程干活不阻塞,但fork这个动作本身在数据量巨大时,可能会因为需要复制页表等元数据而消耗较多CPU时间,如果内存非常大,这个短暂的阻塞时间可能会被感知到。

在实际生产中,很多人会选择将RDB和AOF(记录每一个写操作命令)结合使用,用AOF来尽可能保证数据安全,同时用RDB来做冷备和快速恢复,取长补短,希望这个拆解能让你对RDB转储的来龙去脉有一个清晰的理解。