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 文件来恢复数据。
混合持久化的配置方法如下:
appendonly
参数设置为 yes
,开启 AOF 持久化。
save
参数设置为你需要的值,开启 RDB 持久化。例如,你可以设置为 save 900 1
,这样当 900 秒内有至少 1 个 key 发生变化时,Redis 就会创建一个 RDB 文件。
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
命令会阻塞 Redis 服务器,直到 RDB 文件创建完毕为止,在这期间,Redis 无法处理任何其他命令。
BGSAVE
命令会创建一个子进程来进行持久化操作,父进程则继续处理其他命令。这种方式的优点是非阻塞,但需要注意的是,如果在执行 BGSAVE
的过程中,如果再次触发 BGSAVE
或 SAVE
命令,或者尝试执行 BGREWRITEAOF
命令,Redis 会拒绝,因为 Redis 防止同时存在多个子进程进行持久化操作。
在实际使用中,通常推荐使用 BGSAVE
命令,因为它不会阻塞 Redis 服务器。但是,如果你需要立即创建一个数据库的快照,例如用于备份数据,那么可以使用 SAVE
命令。
在 Redis 的配置文件中,有一些参数是和 RDB 持久化相关的,主要包括以下几个:
<seconds> <changes>
对,表示在过去 <seconds>
秒内,如果有 <changes>
次写操作,就自动执行一次 RDB 持久化。例如,save 900 1
表示在过去 900 秒内,如果有 1 次写操作,就自动执行一次 RDB 持久化。
yes
,那么当 RDB 持久化发生错误时,Redis 会停止所有写操作。
yes
,那么 Redis 会使用 LZF 算法对 RDB 文件进行压缩,以减少 RDB 文件的大小。
yes
,那么 Redis 会在 RDB 文件的末尾添加一个 CRC64 校验和,用于在载入 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 重写的过程主要包括以下几个步骤:
需要注意的是,AOF 重写虽然有很多好处,但是它也是一个非常消耗资源的操作,特别是在数据集很大的时候。因此,你应该根据你的实际情况,合理地触发 AOF 重写。例如,你可以在 Redis 负载较低的时候,或者在有足够的磁盘空间的时候,触发 AOF 重写。
AOF 重写过程中,Redis 主进程还会继续处理客户端的命令。为了保证数据的一致性,所有修改数据的命令仍然会被追加到旧的 AOF 文件。当新的 AOF 文件创建完毕,旧的 AOF 文件被替换后,这些命令会被再次写入到新的 AOF 文件。
Redis 中与 AOF 持久化相关的命令主要有以下几个:
always
表示每次有写命令就立即同步到磁盘,everysec
表示每秒同步一次,no
表示完全由操作系统来决定何时同步。
以上就是 Redis 中和 AOF 持久化相关的主要命令。你可以根据你的实际需求,使用这些命令来控制 AOF 持久化的行为。
在 Redis 的配置文件中,有一些参数是和 AOF 持久化相关的,主要包括以下几个:
yes
,那么 Redis 会开启 AOF 持久化。
always
表示每次有写命令就立即同步到磁盘;everysec
表示每秒同步一次;no
表示完全由操作系统来决定何时同步。
yes
,那么在执行 AOF 重写时,Redis 会暂停同步 AOF 文件。
auto-aof-rewrite-percentage
%,并且 AOF 文件的大小至少为 auto-aof-rewrite-min-size
时,Redis 会自动触发 AOF 重写。
以上就是 Redis 中和 AOF 持久化相关的主要参数。你可以根据你的实际需求,调整这些参数的值,以达到最佳的持久化效果。
Redis 的 AOF 持久化的源码主要分布在 aof.c
和 redis.c
两个文件中。以下是一些主要的函数和它们的作用:
appendfsync
配置选项的值来决定何时进行同步。
以上就是 Redis AOF 持久化的主要源码部分。需要注意的是,这只是一个简单的概述,实际的源码会更复杂,包括很多错误处理和优化。如果你想深入理解 Redis 的 AOF 持久化,建议你直接阅读源码。
AOF 持久化的优点:
AOF 持久化的缺点:
使用 AOF 持久化时,需要注意以下几点:
appendfsync
参数决定了数据同步到磁盘的频率。always
可以提供最高的数据安全性,但会降低写性能;everysec
提供了较好的折中方案,既可以保证一定的数据安全性,又不会太大影响写性能;no
则完全依赖操作系统来决定何时同步,虽然写性能最高,但数据安全性最低。AOF 和 RDB 是两种不同的持久化方式,各有优缺点。你应该根据你的实际需求来选择使用哪种持久化方式。如果你需要最高的数据安全性,那么应该选择 AOF 持久化。如果你更关心性能和效率,那么应该选择 RDB 持久化。当然,你也可以同时开启 AOF 和 RDB 持久化,以便兼顾数据安全性和效率。