持久化机制-RDB

那么,今天我们就来一起了解一下RDB快照,看看它是什么,为什么它重要,以及它是如何工作的。

RDB

快照的含义

首先,我们来解释一下“快照”这个概念。你可以把“快照”理解为某个时刻的数据存储“图片”。也就是说,它是Redis在某个特定时间点保存下来的数据库状态。当你执行RDB快照时,Redis会把当前内存中的所有数据持久化(保存)到硬盘中。

举个例子:

假设你正在用Redis存储学生成绩数据。你在Redis中记录了“学生A”得分90分,“学生B”得分85分。现在,如果你做了一个RDB快照,就相当于在某个时间点将这个数据保存到硬盘中,以便将来需要的时候恢复。

为什么需要这种“快照”?因为Redis是一个内存数据库,数据是存储在内存中的。如果Redis崩溃或发生其他故障,内存中的数据就会丢失。通过RDB快照,我们可以在硬盘上保存数据的副本,保证数据不会丢失。

RDB记录了什么

RDB 和 AOF 记录的东西有何不同呢?

RDB 将整个 Redis 数据库的某个瞬间的状态保存为一个二进制文件,这个文件包含了从启动到快照时的所有数据。也就是说,RDB 记录的是某一瞬间的实际的数据。

而 AOF则是以日志的形式记录每个写操作。每当你执行一次写操作(比如SETDEL等),AOF就会将这个操作追加到文件的末尾,AOF记录的是每一条命令,并不是实际的数据。

AOF 记录的是命令,RDB 记录的是实际数据,所以在进行数据恢复的时候,RDB 的速度就会快一些。因为 AOF 恢复数据数据重新执行命令,而 RDB 恢复数据只需要把 RDB 文件读入内存就可以。

RDB 如何使用

我们一般使用两个命令来生成 RDB 快照文件:

  • bgsave:这个命令会在后台生成RDB文件,执行完这个命令后,Redis会创建一个新的进程来处理生成快照的工作,而不会阻塞当前的操作。这样,你可以继续执行其他操作,不会影响Redis的性能。
  • save:这个命令会阻塞当前的操作,直到快照文件生成完毕为止。在执行过程中,Redis会暂停所有其他操作,直到文件完全写入硬盘。所以,如果执行的过程很长,主线程就会被阻塞。

所以,这两个命令的区别,就在于会不会阻塞主线程。另外,这两个命令是用来生成 RDB 文件的,如果涉及到加载 RDB 文件,则是在服务器刚刚启动的时候就会执行加载。

执行快照的频率

RDB快照的生成频率可以根据Redis配置进行调整。以下是Redis默认配置:

save 900 1
save 300 10
save 60 10000
Plain
  • 每隔900秒(15分钟),如果有至少1次写操作,Redis会生成一次快照。
  • 每隔300秒(5分钟),如果有至少10次写操作,Redis会生成一次快照。
  • 每隔60秒(1分钟),如果有至少10000次写操作,Redis会生成一次快照。

一般在使用 RDB 的时候,都会使用第二种策略,也就是每 5 分钟生成一次快照。

如果我们设置 RDB 快照的频率太高,会发生什么问题呢?

RDB 快照是一个比较耗费资源的操作,这个操作是很重的,特别是在数据量很大的情况下。因为每次执行快照时,Redis需要将所有数据从内存写入磁盘。如果快照频率设置得过高,可能会导致Redis性能下降,影响系统的响应时间。

所以,如果某个时刻 redis 服务崩溃了,RDB 丢失的数据要比 AOF 多得多,因为 RDB 中的数据是每 5 分钟保存一次,而 AOF 的三种写回策略是以秒为单位的。

执行快照的过程

执行bgsave的过程中,主线程可以处理操作命令,修改数据吗?

你可能会想,“既然bgsave命令在执行快照的时候需要把Redis的数据保存到磁盘,那么这个过程是不是会让Redis暂停,不能再做其他事情了呢?”其实,答案是否定的。

当我们执行bgsave命令时,Redis会通过一种叫做后台保存的机制将当前数据快照保存到磁盘。你可以把这个过程想象成是在后台执行一个保存任务,但 Redis 的主线程(也就是平时用来处理客户端请求的那个线程)并不会停下来,而是依旧可以接收客户端的请求、处理命令、修改数据。

这就引出了下一个问题,既然主线程在执行bgsave的同时,依旧在修改数据,RDB快照又是怎么做到的数据一致性的呢?

写时复制

为了让主线程在执行bgsave时继续处理请求并修改数据,而不影响正在进行的快照操作,Redis使用了写时复制技术,这个技术我们在 AOF 篇也讲到过了。

简单来说,写时复制的核心思想是:当主线程需要修改某个内存数据时,它并不会直接修改原有的内存数据,而是将原来的数据复制到一个新的地方,然后对新的副本进行修改。这就确保了快照过程中,原始数据始终保持不变,直到快照过程完成。

举个例子,假设在执行bgsave命令时,Redis需要保存一份用户数据到磁盘。这时,主线程继续接收新的请求,并修改了某个用户的姓名信息。写时复制技术会先复制原有数据,然后在新副本上修改姓名信息,而不会直接影响快照过程中正在保存的原始数据。

写时复制的缺点

当然,写时复制也是优缺点的。

这里的关键就在于:即便主线程进行了写时复制,原始数据仍然不会被修改,快照保存的依旧是修改之前的内存数据,而不是修改后的副本。

这就像是你拍了一张照片,这张照片捕捉的是某一时刻的场景,而不是之后发生的变化。即便之后有新的变化,快照中的数据也不会受到影响。

bgsave执行的过程中,如果主线程修改了某个键的值,写时复制会确保快照保存的是修改前的那个值,而不是修改后的值,所以修改之后的值只能交给下一次快照来保存了。

写时复制的极端情况

写时复制会导致内存占用增加,极端情况下占用的内存是原来的两倍。

在写时复制的机制下,如果在bgsave执行过程中,主线程修改了大量的数据,那么每一项修改都需要复制一份新的数据副本。这意味着,如果所有的数据都被修改,那么内存中的原始数据和副本数据会同时存在,从而导致内存占用翻倍。

举个简单的例子,假设Redis内存中有10GB的数据,在执行bgsave时,如果主线程修改了所有数据,那么Redis就需要同时维护两份数据(原始数据和修改后的副本),总共会占用20GB的内存。这就是写时复制的“代价”。

混合持久化

我们先来看一个问题:

如果 RDB 快照的保存频率设置得太高,Redis会频繁地执行持久化操作。这样虽然可以减少数据丢失的风险,但频繁的RDB保存操作会占用大量的CPU资源,影响系统的整体性能。

如果 RDB 快照的保存频率设置得太低,那么在Redis发生故障时,你可能会丢失较多的数据。

为了解决这个问题,Redis引入了 混合持久化 的概念,也就是将 AOF 和 RDB 进行结合。

关于混合持久化

什么是混合持久化?

混合持久化是Redis结合RDB和AOF两种持久化方式的一个方案。通过混合持久化,Redis能够在既保留RDB高效的快照特性,又能利用AOF保证更高的数据实时性。

简而言之,混合持久化的核心思想是:通过RDB生成数据的快照,并将这些快照和AOF日志结合起来,以提供更高的持久化性能和更低的数据丢失风险

如何开启混合持久化?

要开启混合持久化,我们需要在Redis的配置文件中进行如下设置:

aof-use-rdb-preamble yes
Bash

混合持久化的具体过程

让我们看一下混合持久化是如何在 Redis 中进行操作的。

首先,Redis会创建一个RDB快照,这是Redis在某一时刻内存数据的完整拷贝。这个快照将保存到磁盘上,确保数据的持久化。

同时,Redis还会将对数据的修改操作以日志的形式写入AOF文件。

在混合持久化模式下,Redis会在执行RDB快照的同时,将AOF日志文件中的操作命令一起保存。这样,RDB提供了一个“数据快照”,而AOF则记录了“写操作”。

也就是说,混合持久化中,AOF文件前半部分保存的是 RDB 格式的全量数据,后半部分是 AOF 的增量数据。

当Redis重启时,首先会加载RDB快照中的数据,然后通过AOF文件中的写操作日志恢复所有的数据更改。这样,可以保证数据在恢复过程中既能保证一致性,又能最大程度地减少数据丢失。

混合持久化的好处

当使用混合持久化之后,启动 redis 加载数据时,因为文件的前半部分内容是 RDB 内容,所以加载起来就会非常快。当 RDB 部分的内容被加载完之后,再去加载 AOF 的内容,这部分内容是后台子进程重写 AOF 文件的时候主线程处理的命令,这样就能使得数据更少的丢失。

发表评论

后才能评论