Redis 作为一种内存数据库,其高速度的读写性能吸引了大量的用户。然而,作为数据库,数据的安全性也是我们需要考虑的重要因素。如果 Redis 仅仅将数据存储在内存中,那么一旦发生断电或者系统崩溃等情况,数据将会丢失,这对于任何一个系统来说都是无法接受的。因此,Redis 提供了持久化机制来保证数据的安全性。在这篇博客中,我们将详细介绍 Redis 的两种持久化机制:RDB 和 AOF,以及它们的工作原理、使用场景和优缺点。
Redis 是个基于内存的数据库。那服务一旦宕机,内存中数据必将全部丢失。所以丢失数据的恢复对于 Redis 是十分重要的,我们首先想到是可以从数据库中恢复,但是在由 Redis 宕机时(说明相关工作正在运行)且数据量很大情况下,从数据库恢复的话,会为数据库带来巨大的压力,进而导致程序相应缓慢。因此实现数据的持久化,避免从后端数据库中恢复数据,对于Redis 是十分必要的。
此外,Redis 可以通过创建快照来获得存储在内存里面的数据。创建快照之后,可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本(Redis 主从结构,主要用来提高 Redis 性能),还可以将快照留在原地以便重启服务器的时候使用,其中 Redis 最常用的快照持久化机制分为两种,即 RDB 与 AOF。
在 Redis 中,可以同时开启 RDB 和 AOF 持久化,这种方式被称为混合持久化。混合持久化结合了 RDB 和 AOF 的优点,既可以提供高效的数据备份(RDB),又可以提供高度的数据安全性(AOF)。
当混合持久化开启时,Redis 会优先使用 AOF 文件来恢复数据,因为 AOF 文件的数据通常比 RDB 文件的数据更完整。如果 AOF 文件不存在,那么 Redis 会使用 RDB 文件来恢复数据。
混合持久化的配置方法如下:
在 redis.conf 配置文件中,将 appendonly
参数设置为 yes
,开启 AOF 持久化。
将 save
参数设置为你需要的值,开启 RDB 持久化。例如,你可以设置为 save 900 1
,这样当 900 秒内有至少 1 个 key 发生变化时,Redis 就会创建一个 RDB 文件。
(可选)如果你希望在 Redis 重启时,能够尽可能快地加载数据,你可以将 aof-use-rdb-preamble
参数设置为 yes
。这样,AOF 文件的开头会包含一个 RDB 数据段,Redis 可以先快速地加载这个数据段,然后再加载 AOF 文件的剩余部分。
需要注意的是,虽然混合持久化可以提供更高的数据安全性,但同时开启 RDB 和 AOF 持久化会消耗更多的磁盘空间和 I/O 资源。因此,你应该根据你的实际需求和资源情况,来决定是否使用混合持久化。
RDB 持久化是通过创建数据集的时间点快照来实现的。在指定的时间间隔内,如果满足指定的写操作数量,Redis 就会在后台启动一个新的子进程,将所有数据写入到一个临时文件中,当临时文件写入完成后,再替换原来的文件,达到数据持久化的目的。RDB 是默认的持久化方式,它的优点是可以最大化 Redis 的性能,且 RDB 文件非常适合用于数据备份,或者将数据迁移到另一个 Redis 实例。但是,如果你需要更高的数据安全性,比如不能丢失任何修改操作,那么 AOF 持久化可能更适合你。
Redis 数据库的 RDB 持久化方式是一种快照式的数据备份方式。在指定的时间间隔内,如果满足指定的写操作数量,Redis 就会在后台启动一个新的子进程,将当前所有数据写入到一个临时文件中,当临时文件写入完成后,再替换原来的 RDB 文件,达到数据持久化的目的。
SAVE
或 BGSAVE
命令,来决定是否需要执行 RDB 持久化。需要注意的是,这个过程中的很多细节,例如如何创建子进程,如何写入临时文件,如何替换 RDB 文件,都是由操作系统来完成的,Redis 只需要调用相应的系统调用即可。
Redis 中与 RDB 持久化相关的命令主要有以下两个:
SAVE:该命令会立即执行一个 RDB 持久化操作,保存当前数据库的所有数据到磁盘。需要注意的是,SAVE
命令会阻塞 Redis 服务器,直到 RDB 文件创建完毕为止,在这期间,Redis 无法处理任何其他命令。
BGSAVE:该命令会在后台异步执行一个 RDB 持久化操作。BGSAVE
命令会创建一个子进程来进行持久化操作,父进程则继续处理其他命令。这种方式的优点是非阻塞,但需要注意的是,如果在执行 BGSAVE
的过程中,如果再次触发 BGSAVE
或 SAVE
命令,或者尝试执行 BGREWRITEAOF
命令,Redis 会拒绝,因为 Redis 防止同时存在多个子进程进行持久化操作。
在实际使用中,通常推荐使用 BGSAVE
命令,因为它不会阻塞 Redis 服务器。但是,如果你需要立即创建一个数据库的快照,例如用于备份数据,那么可以使用 SAVE
命令。
在 Redis 的配置文件中,有一些参数是和 RDB 持久化相关的,主要包括以下几个:
save:这个参数用于设置自动触发 RDB 持久化的条件。它的值是一个或多个
对,表示在过去
秒内,如果有
次写操作,就自动执行一次 RDB 持久化。例如,save 900 1
表示在过去 900 秒内,如果有 1 次写操作,就自动执行一次 RDB 持久化。
stop-writes-on-bgsave-error:这个参数用于设置当 RDB 持久化发生错误时,是否停止写操作。如果它的值为 yes
,那么当 RDB 持久化发生错误时,Redis 会停止所有写操作。
rdbcompression:这个参数用于设置是否对 RDB 文件进行压缩。如果它的值为 yes
,那么 Redis 会使用 LZF 算法对 RDB 文件进行压缩,以减少 RDB 文件的大小。
rdbchecksum:这个参数用于设置是否对 RDB 文件进行校验和检查。如果它的值为 yes
,那么 Redis 会在 RDB 文件的末尾添加一个 CRC64 校验和,用于在载入 RDB 文件时检查数据的完整性。
dbfilename:这个参数用于设置 RDB 文件的文件名。
dir:这个参数用于设置 RDB 文件的保存目录。
以上就是 Redis 中和 RDB 持久化相关的主要参数。你可以根据你的实际需求,调整这些参数的值,以达到最佳的持久化效果。
对于 Redis 的 RDB 持久化的源码,主要涉及到两个函数:rdbSave
和 rdbSaveBackground
。
rdbSave
函数是执行 RDB 持久化的主要函数,它会将当前数据库的数据保存到指定的 RDB 文件中。这个函数会阻塞 Redis 服务器,直到 RDB 文件创建完毕为止。
rdbSaveBackground
函数则是在后台执行 RDB 持久化的函数,它会创建一个子进程来执行 rdbSave
函数,这样父进程就可以继续处理客户端的请求。
以下是这两个函数的简化版的源码:
/* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
int rdbSave(char *filename) {
/* ...省略创建和写入 RDB 文件的代码... */
return REDIS_OK;
}
/* Save the DB in background. Return REDIS_ERR on error, REDIS_OK on success */
int rdbSaveBackground(char *filename) {
pid_t childpid;
long long start;
/* ...省略一些错误处理和日志记录的代码... */
/* Create a child process that will actually perform the dump. */
childpid = fork();
if (childpid == 0) {
/* Child */
closeListeningSockets(0);
redisSetProcTitle("redis-rdb-bgsave");
if (rdbSave(filename) == REDIS_OK) {
exitFromChild(0);
} else {
exitFromChild(1);
}
} else {
/* Parent */
/* ...省略一些错误处理和日志记录的代码... */
return REDIS_OK;
}
return REDIS_ERR;
}
以上就是 Redis RDB 持久化的主要源码。需要注意的是,这里省略了很多细节,例如如何创建 RDB 文件,如何将数据写入到 RDB 文件,以及如何处理各种可能的错误等。如果你想深入了解这部分的源码,可以直接查看 Redis 的源码。
RDB 持久化的优点:
RDB 持久化的缺点:
RDB注意事项(特征):
AOF 持久化记录了服务器接收到的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。AOF 文件的更新操作是追加模式,因此对于写入命令的丢失问题,AOF 文件在写入时就已经将数据保存到了磁盘,大大降低了丢失数据的可能性。并且,Redis 还可以对 AOF 文件进行后台重写,使得 AOF 文件的体积保持在最小。但是,相比于 RDB,AOF 文件通常更大,且恢复速度更慢。
Redis 的 AOF(Append Only File)持久化过程主要包括以下几个步骤:
SET
、DEL
等)时,它会将这个命令追加到 AOF 缓冲区。appendfsync
参数)来决定何时将 AOF 缓冲区的内容写入到磁盘。有三种可能的配置:每次有写命令就立即写入磁盘(always
);每秒写入一次(everysec
);完全由操作系统来决定何时写入(no
)。auto-aof-rewrite-percentage
和 auto-aof-rewrite-min-size
参数)自动触发。需要注意的是,虽然 AOF 持久化在默认配置下可以提供更好的数据安全性(只会丢失一秒的数据),但它需要更多的磁盘空间,且可能会降低 Redis 的写性能。
AOF 持久化的重写机制主要是为了减小 AOF 文件的大小。随着 Redis 的运行,AOF 文件中记录的命令会越来越多,文件的大小也会越来越大。但是,很多旧的命令可能已经不再需要,因为它们修改的数据可能已经被后来的命令再次修改。因此,Redis 提供了 AOF 重写机制,可以创建一个新的 AOF 文件,这个新的 AOF 文件可以达到和原来的 AOF 文件相同的效果,但文件的大小会小很多。
AOF 持久化的重写主要有两个作用:
减小 AOF 文件的大小:随着 Redis 的运行,AOF 文件中记录的命令会越来越多,文件的大小也会越来越大。但是,很多旧的命令可能已经不再需要,因为它们修改的数据可能已经被后来的命令再次修改。AOF 重写可以创建一个新的 AOF 文件,这个新的 AOF 文件可以达到和原来的 AOF 文件相同的效果,但文件的大小会小很多。
提高数据恢复的速度:如果 AOF 文件中的命令非常多,那么在 Redis 启动时,需要花费很长的时间来重新执行这些命令,以恢复数据。通过 AOF 重写,可以减少 AOF 文件中的命令数量,从而提高数据恢复的速度。
AOF 重写的过程主要包括以下几个步骤:
需要注意的是,AOF 重写虽然有很多好处,但是它也是一个非常消耗资源的操作,特别是在数据集很大的时候。因此,你应该根据你的实际情况,合理地触发 AOF 重写。例如,你可以在 Redis 负载较低的时候,或者在有足够的磁盘空间的时候,触发 AOF 重写。
AOF 重写过程中,Redis 主进程还会继续处理客户端的命令。为了保证数据的一致性,所有修改数据的命令仍然会被追加到旧的 AOF 文件。当新的 AOF 文件创建完毕,旧的 AOF 文件被替换后,这些命令会被再次写入到新的 AOF 文件。
Redis 中与 AOF 持久化相关的命令主要有以下几个:
BGREWRITEAOF:该命令用于在后台异步执行一个 AOF 重写操作。AOF 重写可以减小 AOF 文件的大小。
CONFIG SET appendonly yes/no:该命令用于开启或关闭 AOF 持久化功能。需要注意的是,关闭 AOF 持久化后,Redis 将只能依赖 RDB 持久化来保存数据。
CONFIG SET appendfsync always/everysec/no:该命令用于设置 AOF 持久化的同步策略。always
表示每次有写命令就立即同步到磁盘,everysec
表示每秒同步一次,no
表示完全由操作系统来决定何时同步。
以上就是 Redis 中和 AOF 持久化相关的主要命令。你可以根据你的实际需求,使用这些命令来控制 AOF 持久化的行为。
在 Redis 的配置文件中,有一些参数是和 AOF 持久化相关的,主要包括以下几个:
appendonly:这个参数用于设置是否开启 AOF 持久化。如果它的值为 yes
,那么 Redis 会开启 AOF 持久化。
appendfilename:这个参数用于设置 AOF 文件的文件名。
appendfsync:这个参数用于设置 AOF 持久化的同步策略。有三种可能的值:always
表示每次有写命令就立即同步到磁盘;everysec
表示每秒同步一次;no
表示完全由操作系统来决定何时同步。
no-appendfsync-on-rewrite:这个参数用于设置在执行 AOF 重写时,是否暂停同步 AOF 文件。如果它的值为 yes
,那么在执行 AOF 重写时,Redis 会暂停同步 AOF 文件。
auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size:这两个参数用于设置自动触发 AOF 重写的条件。当 AOF 文件的大小是上次重写后的大小的 auto-aof-rewrite-percentage
%,并且 AOF 文件的大小至少为 auto-aof-rewrite-min-size
时,Redis 会自动触发 AOF 重写。
以上就是 Redis 中和 AOF 持久化相关的主要参数。你可以根据你的实际需求,调整这些参数的值,以达到最佳的持久化效果。
Redis 的 AOF 持久化的源码主要分布在 aof.c
和 redis.c
两个文件中。以下是一些主要的函数和它们的作用:
flushAppendOnlyFile:这个函数负责将 AOF 缓冲区的内容写入到磁盘。它会根据 appendfsync
配置选项的值来决定何时进行同步。
feedAppendOnlyFile:这个函数负责将执行的命令追加到 AOF 缓冲区。它会将命令和它的参数转换为 Redis 协议格式,然后追加到 AOF 缓冲区。
rewriteAppendOnlyFileBackground:这个函数负责在后台启动一个 AOF 重写操作。它会 fork 出一个子进程来进行 AOF 重写。
rewriteAppendOnlyFile:这个函数负责执行 AOF 重写操作。它会遍历数据库中的所有键,然后生成相应的命令并写入到新的 AOF 文件。
loadAppendOnlyFile:这个函数负责在 Redis 启动时加载 AOF 文件。它会读取 AOF 文件中的所有命令,然后重新执行这些命令,以此来恢复数据。
以上就是 Redis AOF 持久化的主要源码部分。需要注意的是,这只是一个简单的概述,实际的源码会更复杂,包括很多错误处理和优化。如果你想深入理解 Redis 的 AOF 持久化,建议你直接阅读源码。
AOF 持久化的优点:
AOF 持久化的缺点:
文件体积更大:相比于 RDB 持久化,AOF 持久化的文件通常更大。
处理速度较慢:由于需要记录更多的信息,所以 AOF 持久化的处理速度通常会慢于 RDB 持久化。
可能存在冗余信息:在大量写入操作的情况下,AOF 文件中可能会存在大量的冗余信息。
AOF 重写需要消耗更多的 CPU 和内存资源:AOF 重写过程中,需要 fork 出一个子进程,这会消耗大量的 CPU 和内存资源。
使用 AOF 持久化时,需要注意以下几点:
appendfsync
参数决定了数据同步到磁盘的频率。always
可以提供最高的数据安全性,但会降低写性能;everysec
提供了较好的折中方案,既可以保证一定的数据安全性,又不会太大影响写性能;no
则完全依赖操作系统来决定何时同步,虽然写性能最高,但数据安全性最低。AOF 和 RDB 是两种不同的持久化方式,各有优缺点。你应该根据你的实际需求来选择使用哪种持久化方式。如果你需要最高的数据安全性,那么应该选择 AOF 持久化。如果你更关心性能和效率,那么应该选择 RDB 持久化。当然,你也可以同时开启 AOF 和 RDB 持久化,以便兼顾数据安全性和效率。