Redis持久化机制

2023-10-16 14:38:30 浏览数 (1)

Redis 作为一种内存数据库,其高速度的读写性能吸引了大量的用户。然而,作为数据库,数据的安全性也是我们需要考虑的重要因素。如果 Redis 仅仅将数据存储在内存中,那么一旦发生断电或者系统崩溃等情况,数据将会丢失,这对于任何一个系统来说都是无法接受的。因此,Redis 提供了持久化机制来保证数据的安全性。在这篇博客中,我们将详细介绍 Redis 的两种持久化机制:RDB 和 AOF,以及它们的工作原理、使用场景和优缺点。

1、Redis持久化机制
1.1、Redis持久化机制简介

Redis 是个基于内存的数据库。那服务一旦宕机,内存中数据必将全部丢失。所以丢失数据的恢复对于 Redis 是十分重要的,我们首先想到是可以从数据库中恢复,但是在由 Redis 宕机时(说明相关工作正在运行)且数据量很大情况下,从数据库恢复的话,会为数据库带来巨大的压力,进而导致程序相应缓慢。因此实现数据的持久化,避免从后端数据库中恢复数据,对于Redis 是十分必要的。

此外,Redis 可以通过创建快照来获得存储在内存里面的数据。创建快照之后,可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本(Redis 主从结构,主要用来提高 Redis 性能),还可以将快照留在原地以便重启服务器的时候使用,其中 Redis 最常用的快照持久化机制分为两种,即 RDB 与 AOF。

1.2、混合使用 RDB 和 AOF

在 Redis 中,可以同时开启 RDB 和 AOF 持久化,这种方式被称为混合持久化。混合持久化结合了 RDB 和 AOF 的优点,既可以提供高效的数据备份(RDB),又可以提供高度的数据安全性(AOF)。

当混合持久化开启时,Redis 会优先使用 AOF 文件来恢复数据,因为 AOF 文件的数据通常比 RDB 文件的数据更完整。如果 AOF 文件不存在,那么 Redis 会使用 RDB 文件来恢复数据。

混合持久化的配置方法如下:

  1. 在 redis.conf 配置文件中,将 appendonly 参数设置为 yes,开启 AOF 持久化。
  2. save 参数设置为你需要的值,开启 RDB 持久化。例如,你可以设置为 save 900 1,这样当 900 秒内有至少 1 个 key 发生变化时,Redis 就会创建一个 RDB 文件。
  3. (可选)如果你希望在 Redis 重启时,能够尽可能快地加载数据,你可以将 aof-use-rdb-preamble 参数设置为 yes。这样,AOF 文件的开头会包含一个 RDB 数据段,Redis 可以先快速地加载这个数据段,然后再加载 AOF 文件的剩余部分。

需要注意的是,虽然混合持久化可以提供更高的数据安全性,但同时开启 RDB 和 AOF 持久化会消耗更多的磁盘空间和 I/O 资源。因此,你应该根据你的实际需求和资源情况,来决定是否使用混合持久化。


2、RDB(Redis DataBase)
2.1、RDB持久化简介

RDB 持久化是通过创建数据集的时间点快照来实现的。在指定的时间间隔内,如果满足指定的写操作数量,Redis 就会在后台启动一个新的子进程,将所有数据写入到一个临时文件中,当临时文件写入完成后,再替换原来的文件,达到数据持久化的目的。RDB 是默认的持久化方式,它的优点是可以最大化 Redis 的性能,且 RDB 文件非常适合用于数据备份,或者将数据迁移到另一个 Redis 实例。但是,如果你需要更高的数据安全性,比如不能丢失任何修改操作,那么 AOF 持久化可能更适合你。

2.2、RDB持久化过程

Redis 数据库的 RDB 持久化方式是一种快照式的数据备份方式。在指定的时间间隔内,如果满足指定的写操作数量,Redis 就会在后台启动一个新的子进程,将当前所有数据写入到一个临时文件中,当临时文件写入完成后,再替换原来的 RDB 文件,达到数据持久化的目的。

  1. 判断是否需要执行 RDB 持久化:Redis 会根据配置文件中的规则(例如,每过多少秒,如果有多少次写操作,就进行一次 RDB 持久化),以及是否收到了 SAVEBGSAVE 命令,来决定是否需要执行 RDB 持久化。
  2. 创建子进程:如果需要执行 RDB 持久化,Redis 会创建一个子进程来进行持久化操作。这样做的好处是,父进程可以继续处理客户端的请求,而不需要等待持久化操作完成。
  3. 写入临时文件:子进程会将当前所有数据写入到一个临时文件中。这个临时文件是一个二进制文件,其中包含了 Redis 在持久化开始时的所有数据。
  4. 替换原来的 RDB 文件:当临时文件写入完成后,子进程会用这个临时文件替换原来的 RDB 文件。这样做的好处是,即使在替换过程中发生错误(例如,磁盘空间不足),原来的 RDB 文件也不会被破坏。
  5. 通知父进程:最后,子进程会通知父进程它已经完成了持久化操作。父进程在接到这个通知后,会更新自己的状态,例如,它会记录下最后一次成功执行 RDB 持久化的时间。

需要注意的是,这个过程中的很多细节,例如如何创建子进程,如何写入临时文件,如何替换 RDB 文件,都是由操作系统来完成的,Redis 只需要调用相应的系统调用即可。

2.3、RDB持久化命令

Redis 中与 RDB 持久化相关的命令主要有以下两个:

  1. SAVE:该命令会立即执行一个 RDB 持久化操作,保存当前数据库的所有数据到磁盘。需要注意的是,SAVE 命令会阻塞 Redis 服务器,直到 RDB 文件创建完毕为止,在这期间,Redis 无法处理任何其他命令。
  2. BGSAVE:该命令会在后台异步执行一个 RDB 持久化操作。BGSAVE 命令会创建一个子进程来进行持久化操作,父进程则继续处理其他命令。这种方式的优点是非阻塞,但需要注意的是,如果在执行 BGSAVE 的过程中,如果再次触发 BGSAVESAVE 命令,或者尝试执行 BGREWRITEAOF 命令,Redis 会拒绝,因为 Redis 防止同时存在多个子进程进行持久化操作。

在实际使用中,通常推荐使用 BGSAVE 命令,因为它不会阻塞 Redis 服务器。但是,如果你需要立即创建一个数据库的快照,例如用于备份数据,那么可以使用 SAVE 命令。

2.4、RDB参数设置

在 Redis 的配置文件中,有一些参数是和 RDB 持久化相关的,主要包括以下几个:

  1. save:这个参数用于设置自动触发 RDB 持久化的条件。它的值是一个或多个 <seconds> <changes> 对,表示在过去 <seconds> 秒内,如果有 <changes> 次写操作,就自动执行一次 RDB 持久化。例如,save 900 1 表示在过去 900 秒内,如果有 1 次写操作,就自动执行一次 RDB 持久化。
  2. stop-writes-on-bgsave-error:这个参数用于设置当 RDB 持久化发生错误时,是否停止写操作。如果它的值为 yes,那么当 RDB 持久化发生错误时,Redis 会停止所有写操作。
  3. rdbcompression:这个参数用于设置是否对 RDB 文件进行压缩。如果它的值为 yes,那么 Redis 会使用 LZF 算法对 RDB 文件进行压缩,以减少 RDB 文件的大小。
  4. rdbchecksum:这个参数用于设置是否对 RDB 文件进行校验和检查。如果它的值为 yes,那么 Redis 会在 RDB 文件的末尾添加一个 CRC64 校验和,用于在载入 RDB 文件时检查数据的完整性。
  5. dbfilename:这个参数用于设置 RDB 文件的文件名。
  6. dir:这个参数用于设置 RDB 文件的保存目录。

以上就是 Redis 中和 RDB 持久化相关的主要参数。你可以根据你的实际需求,调整这些参数的值,以达到最佳的持久化效果。

2.5、RDB源码简述

对于 Redis 的 RDB 持久化的源码,主要涉及到两个函数:rdbSaverdbSaveBackground

rdbSave 函数是执行 RDB 持久化的主要函数,它会将当前数据库的数据保存到指定的 RDB 文件中。这个函数会阻塞 Redis 服务器,直到 RDB 文件创建完毕为止。

rdbSaveBackground 函数则是在后台执行 RDB 持久化的函数,它会创建一个子进程来执行 rdbSave 函数,这样父进程就可以继续处理客户端的请求。

以下是这两个函数的简化版的源码:

代码语言:javascript复制
/* 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 的源码。

2.6、RDB优缺点

RDB 持久化的优点:

  1. RDB 是一个非常紧凑的文件,代表了 Redis 在某个时间点的数据快照。
  2. RDB 可以最大化 Redis 的性能,父进程在保存 RDB 文件时唯一要做的就是 fork 一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无需执行任何磁盘 I/O 操作。
  3. RDB 非常适用于备份场景,你可以在夜间进行备份,因为 RDB 文件只表示某个时间点的数据快照,所以它对于灾难恢复非常有用。

RDB 持久化的缺点:

  1. 如果你需要尽可能避免在 Redis 发生故障时丢失数据,那么 RDB 不是一个好的选择。因为 RDB 文件是定期产生的,如果 Redis 发生故障,那么你将丢失最后一次快照以来的所有数据。
  2. RDB 需要 fork 子进程来进行持久化,如果数据集很大时,fork 可能会非常耗时,造成服务器阻塞。
2.7、RDB注意事项

RDB注意事项(特征):

  1. RDB 持久化是通过创建数据集的时间点快照来实现的,因此如果在两次快照之间 Redis 发生故障,则这段时间的数据将会丢失。
  2. RDB 文件是在 Redis 内存数据集的一个时间点上生成的,所以它对于数据恢复非常有用,特别是在数据意外丢失的情况下。
  3. RDB 在保存和加载时非常快,因为它是直接由磁盘进行单一的 I/O 操作,不像 AOF 持久化方式需要执行多个命令。
  4. RDB 在备份(master 实例进行 bgsave,然后将 RDB 文件复制到其他地方)或者数据集大的时候,数据恢复速度比 AOF 快。

3、AOF(Append Only File)
3.1、AOF简介

AOF 持久化记录了服务器接收到的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。AOF 文件的更新操作是追加模式,因此对于写入命令的丢失问题,AOF 文件在写入时就已经将数据保存到了磁盘,大大降低了丢失数据的可能性。并且,Redis 还可以对 AOF 文件进行后台重写,使得 AOF 文件的体积保持在最小。但是,相比于 RDB,AOF 文件通常更大,且恢复速度更慢。

3.2、AOFB持久化过程

Redis 的 AOF(Append Only File)持久化过程主要包括以下几个步骤:

  1. 记录写命令:当 Redis 执行一个会改变数据的命令(例如 SETDEL 等)时,它会将这个命令追加到 AOF 缓冲区。
  2. 写入磁盘:Redis 会根据配置(appendfsync 参数)来决定何时将 AOF 缓冲区的内容写入到磁盘。有三种可能的配置:每次有写命令就立即写入磁盘(always);每秒写入一次(everysec);完全由操作系统来决定何时写入(no)。
  3. 文件重写:随着时间的推移,AOF 文件可能会越来越大。Redis 提供了 AOF 重写功能,可以创建一个新的 AOF 文件,这个新的 AOF 文件和原来的 AOF 文件可以达到相同的效果,但体积更小。AOF 重写可以手动触发,也可以根据配置(auto-aof-rewrite-percentageauto-aof-rewrite-min-size 参数)自动触发。
  4. 恢复数据:当 Redis 重启时,它会读取 AOF 文件,然后重新执行 AOF 文件中的所有命令,以此来恢复数据。

需要注意的是,虽然 AOF 持久化在默认配置下可以提供更好的数据安全性(只会丢失一秒的数据),但它需要更多的磁盘空间,且可能会降低 Redis 的写性能。

3.3、AOFB持久化重写

AOF 持久化的重写机制主要是为了减小 AOF 文件的大小。随着 Redis 的运行,AOF 文件中记录的命令会越来越多,文件的大小也会越来越大。但是,很多旧的命令可能已经不再需要,因为它们修改的数据可能已经被后来的命令再次修改。因此,Redis 提供了 AOF 重写机制,可以创建一个新的 AOF 文件,这个新的 AOF 文件可以达到和原来的 AOF 文件相同的效果,但文件的大小会小很多。

AOF 持久化的重写主要有两个作用:

  1. 减小 AOF 文件的大小:随着 Redis 的运行,AOF 文件中记录的命令会越来越多,文件的大小也会越来越大。但是,很多旧的命令可能已经不再需要,因为它们修改的数据可能已经被后来的命令再次修改。AOF 重写可以创建一个新的 AOF 文件,这个新的 AOF 文件可以达到和原来的 AOF 文件相同的效果,但文件的大小会小很多。
  2. 提高数据恢复的速度:如果 AOF 文件中的命令非常多,那么在 Redis 启动时,需要花费很长的时间来重新执行这些命令,以恢复数据。通过 AOF 重写,可以减少 AOF 文件中的命令数量,从而提高数据恢复的速度。

AOF 重写的过程主要包括以下几个步骤:

  1. Redis 主进程 fork 出一个子进程。
  2. 子进程遍历当前数据库中的所有数据,对每一条数据,生成一条或多条等效的命令,然后将这些命令写入到新的 AOF 文件。
  3. 当子进程完成新的 AOF 文件的创建后,它会向主进程发送一个信号,告诉主进程新的 AOF 文件已经创建完毕。
  4. 主进程收到子进程的信号后,会用新的 AOF 文件替换旧的 AOF 文件。

需要注意的是,AOF 重写虽然有很多好处,但是它也是一个非常消耗资源的操作,特别是在数据集很大的时候。因此,你应该根据你的实际情况,合理地触发 AOF 重写。例如,你可以在 Redis 负载较低的时候,或者在有足够的磁盘空间的时候,触发 AOF 重写。

AOF 重写过程中,Redis 主进程还会继续处理客户端的命令。为了保证数据的一致性,所有修改数据的命令仍然会被追加到旧的 AOF 文件。当新的 AOF 文件创建完毕,旧的 AOF 文件被替换后,这些命令会被再次写入到新的 AOF 文件。

3.4、AOF持久化命令

Redis 中与 AOF 持久化相关的命令主要有以下几个:

  1. BGREWRITEAOF:该命令用于在后台异步执行一个 AOF 重写操作。AOF 重写可以减小 AOF 文件的大小。
  2. CONFIG SET appendonly yes/no:该命令用于开启或关闭 AOF 持久化功能。需要注意的是,关闭 AOF 持久化后,Redis 将只能依赖 RDB 持久化来保存数据。
  3. CONFIG SET appendfsync always/everysec/no:该命令用于设置 AOF 持久化的同步策略。always 表示每次有写命令就立即同步到磁盘,everysec 表示每秒同步一次,no 表示完全由操作系统来决定何时同步。

以上就是 Redis 中和 AOF 持久化相关的主要命令。你可以根据你的实际需求,使用这些命令来控制 AOF 持久化的行为。

3.5、AOF参数设置

在 Redis 的配置文件中,有一些参数是和 AOF 持久化相关的,主要包括以下几个:

  1. appendonly:这个参数用于设置是否开启 AOF 持久化。如果它的值为 yes,那么 Redis 会开启 AOF 持久化。
  2. appendfilename:这个参数用于设置 AOF 文件的文件名。
  3. appendfsync:这个参数用于设置 AOF 持久化的同步策略。有三种可能的值:always 表示每次有写命令就立即同步到磁盘;everysec 表示每秒同步一次;no 表示完全由操作系统来决定何时同步。
  4. no-appendfsync-on-rewrite:这个参数用于设置在执行 AOF 重写时,是否暂停同步 AOF 文件。如果它的值为 yes,那么在执行 AOF 重写时,Redis 会暂停同步 AOF 文件。
  5. 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 持久化相关的主要参数。你可以根据你的实际需求,调整这些参数的值,以达到最佳的持久化效果。

3.6、AOF源码简述

Redis 的 AOF 持久化的源码主要分布在 aof.credis.c 两个文件中。以下是一些主要的函数和它们的作用:

  1. flushAppendOnlyFile:这个函数负责将 AOF 缓冲区的内容写入到磁盘。它会根据 appendfsync 配置选项的值来决定何时进行同步。
  2. feedAppendOnlyFile:这个函数负责将执行的命令追加到 AOF 缓冲区。它会将命令和它的参数转换为 Redis 协议格式,然后追加到 AOF 缓冲区。
  3. rewriteAppendOnlyFileBackground:这个函数负责在后台启动一个 AOF 重写操作。它会 fork 出一个子进程来进行 AOF 重写。
  4. rewriteAppendOnlyFile:这个函数负责执行 AOF 重写操作。它会遍历数据库中的所有键,然后生成相应的命令并写入到新的 AOF 文件。
  5. loadAppendOnlyFile:这个函数负责在 Redis 启动时加载 AOF 文件。它会读取 AOF 文件中的所有命令,然后重新执行这些命令,以此来恢复数据。

以上就是 Redis AOF 持久化的主要源码部分。需要注意的是,这只是一个简单的概述,实际的源码会更复杂,包括很多错误处理和优化。如果你想深入理解 Redis 的 AOF 持久化,建议你直接阅读源码。

3.7、AOF优缺点

AOF 持久化的优点:

  1. 数据安全性更高:AOF 持久化可以配置为每执行一次写命令就立即写入磁盘,这样即使发生故障,也只会丢失一次写命令的数据。
  2. 可读性和可写性更好:AOF 文件是一个只追加不修改的日志文件,可以被人类直接阅读。如果文件末尾损坏,可以直接修剪掉损坏部分,不会影响文件的读取

AOF 持久化的缺点:

  1. 文件体积更大:相比于 RDB 持久化,AOF 持久化的文件通常更大。
  2. 处理速度较慢:由于需要记录更多的信息,所以 AOF 持久化的处理速度通常会慢于 RDB 持久化。
  3. 可能存在冗余信息:在大量写入操作的情况下,AOF 文件中可能会存在大量的冗余信息。
  4. AOF 重写需要消耗更多的 CPU 和内存资源:AOF 重写过程中,需要 fork 出一个子进程,这会消耗大量的 CPU 和内存资源。
2.8、AOF注意事项

使用 AOF 持久化时,需要注意以下几点:

  1. 选择合适的 fsync 策略:appendfsync 参数决定了数据同步到磁盘的频率。always 可以提供最高的数据安全性,但会降低写性能;everysec 提供了较好的折中方案,既可以保证一定的数据安全性,又不会太大影响写性能;no 则完全依赖操作系统来决定何时同步,虽然写性能最高,但数据安全性最低。
  2. 定期进行 AOF 重写:随着时间的推移,AOF 文件可能会变得越来越大。定期进行 AOF 重写可以减小 AOF 文件的大小,提高数据恢复的速度。但需要注意的是,AOF 重写是一个消耗资源的操作,应在 Redis 负载较低的时候进行。
  3. 监控 AOF 文件的大小:如果 AOF 文件的大小超过了硬盘的可用空间,那么 Redis 将无法继续写入数据。因此,你应该定期监控 AOF 文件的大小,确保硬盘有足够的可用空间。
  4. 注意 AOF 文件的备份和恢复:你应该定期备份 AOF 文件,以防止数据丢失。在恢复数据时,只需要将备份的 AOF 文件替换到原来的位置,然后重启 Redis 即可。

AOF 和 RDB 是两种不同的持久化方式,各有优缺点。你应该根据你的实际需求来选择使用哪种持久化方式。如果你需要最高的数据安全性,那么应该选择 AOF 持久化。如果你更关心性能和效率,那么应该选择 RDB 持久化。当然,你也可以同时开启 AOF 和 RDB 持久化,以便兼顾数据安全性和效率。

0 人点赞