Redis 持久性

Redis 如何将数据写入磁盘

持久性是指将数据写入持久存储,例如固态磁盘 (SSD)。Redis 提供了一系列持久性选项。其中包括:

  • RDB(Redis 数据库):RDB 持久性会按照指定的时间间隔对数据集执行时间点快照。
  • AOF(仅追加文件):AOF 持久性记录服务器收到的每个写入操作。然后可以在服务器启动时再次重放这些操作,重建原始数据集。命令使用与 Redis 协议本身相同的格式进行记录。
  • 无持久性:您可以完全禁用持久性。这有时在缓存时使用。
  • RDB + AOF:您还可以在同一个实例中结合使用 AOF 和 RDB。

如果您不想考虑这些不同持久性策略之间的权衡,您可能需要考虑Redis Enterprise 的持久性选项,可以使用 UI 进行预先配置。

要了解有关如何评估 Redis 持久性策略的更多信息,请继续阅读。

RDB 优点

  • RDB 是 Redis 数据的一个非常紧凑的单文件时间点表示。RDB 文件非常适合备份。例如,您可能希望每小时存档最近 24 小时内的 RDB 文件,并每天保存 30 天的 RDB 快照。这样,您就可以在发生灾难时轻松恢复数据集的不同版本。
  • RDB 非常适合灾难恢复,它是一个单一的紧凑文件,可以传输到远程数据中心,或者传输到 Amazon S3(可能加密)。
  • RDB 可最大程度地提高 Redis 的性能,因为 Redis 父进程为了持久化所需要做的唯一工作就是派生一个子进程,然后由子进程来完成其余所有工作。父进程永远不会执行磁盘 I/O 或类似操作。
  • 与 AOF 相比,RDB 允许使用大数据集更快地重启。
  • 在副本上,RDB 支持重启和故障转移后的部分重新同步

RDB 缺点

  • 如果您需要尽量减少 Redis 停止工作(例如断电后)时数据丢失的可能性,那么 RDB 并不是一个好选择。您可以配置生成 RDB 的不同保存点(例如,在至少五分钟后对数据集进行 100 次写入后,您可以有多个保存点)。但是,您通常每五分钟或更长时间创建一个 RDB 快照,因此,如果 Redis 因任何原因而未正确关闭而停止工作,您应该准备好丢失最近几分钟的数据。
  • RDB 需要经常使用子进程 fork() 才能将其持久保存在磁盘上。如果数据集很大,fork() 可能会很耗时,如果数据集很大且 CPU 性能不佳,可能会导致 Redis 停止为客户端提供服务几毫秒甚至一秒钟。AOF 也需要 fork(),但频率较低,您可以调整重写日志的频率,而无需牺牲持久性。

AOF 优点

  • 使用 AOF Redis 的持久性更强:您可以采用不同的 fsync 策略:完全不进行 fsync、每秒进行 fsync、每次查询时进行 fsync。使用每秒进行 fsync 的默认策略,写入性能仍然很好。fsync 使用后台线程执行,主线程会在没有 fsync 进行时尽力执行写入,因此您只会丢失一秒钟的写入。
  • AOF 日志是仅附加日志,因此不会出现寻道,也不会在断电时出现损坏问题。即使日志因某种原因(磁盘已满或其他原因)以半写命令结束,redis-check-aof 工具也能够轻松修复它。
  • 当 AOF 太大时,Redis 能够在后台自动重写。重写是完全安全的,因为 Redis 在继续向旧文件追加内容的同时,会使用创建当前数据集所需的最少操作集生成一个全新的文件,一旦第二个文件准备就绪,Redis 就会切换这两个文件并开始向新文件追加内容。
  • AOF 以易于理解和解析的格式逐一记录所有操作的日志。您甚至可以轻松导出 AOF 文件。例如,即使您不小心使用该FLUSHALL命令刷新了所有内容,只要在此期间没有执行日志重写,您仍然可以通过停止服务器、删除最新命令并重新启动 Redis 来保存数据集。

AOF 缺点

  • 对于同一数据集,AOF 文件通常比等效的 RDB 文件更大。
  • 根据确切的 fsync 策略,AOF 可能比 RDB 慢。一般来说,将 fsync 设置为每秒一次时,性能仍然非常高,而禁用 fsync 时,即使在高负载下,它也应该与 RDB 一样快。即使在写入负载巨大的情况下,RDB 仍能够提供更多关于最大延迟的保证。

Redis < 7.0

  • 如果在重写期间对数据库进行写入(这些写入会缓冲在内存中并在最后写入新的 AOF),则 AOF 会使用大量内存。
  • 重写期间到达的所有写入命令都会被写入磁盘两次。
  • Redis 可以在重写结束时冻结写入并将这些写入命令 fsync 到新的 AOF 文件。

好的,那么我应该用什么呢?

一般情况下,如果您想要获得与 PostgreSQL 所能提供的相当的数据安全程度,那么就应该同时使用这两种持久性方法。

如果您非常关心您的数据,但在发生灾难时仍然可以承受几分钟的数据丢失,那么您可以单独使用 RDB。

有很多用户单独使用 AOF,但是我们不鼓励这样做,因为不时地进行 RDB 快照对于进行数据库备份、更快地重启以及在 AOF 引擎出现错误时是一个好主意。

以下部分将详细说明这两种持久性模型。

快照

默认情况下,Redis 将数据集的快照保存在磁盘上,保存在名为 的二进制文件中dump.rdb。您可以配置 Redis,让其每 N 秒保存一次数据集(如果数据集中至少有 M 个更改),或者您可以手动调用SAVEBGSAVE命令。

例如,如果至少有 1000 个键发生变化,此配置将使 Redis 每 60 秒自动将数据集转储到磁盘:

save 60 1000

这种策略称为快照

工作原理

每当 Redis 需要将数据集转储到磁盘时,就会发生以下情况:

  • Redis分叉。我们现在有一个子进程和一个父进程。

  • 子进程开始将数据集写入临时 RDB 文件。

  • 当子进程完成新 RDB 文件的写入后,它将替换旧文件。

这种方法使 Redis 受益于写时复制语义。

仅附加文件

快照的持久性不是很好。如果运行 Redis 的计算机停止运行、电源线发生故障或者您意外损坏了kill -9实例,写入 Redis 的最新数据将会丢失。虽然这对于某些应用程序来说可能不是什么大问题,但有些用例需要完全的持久​​性,在这些情况下,仅使用 Redis 快照并不是一个可行的选择。

仅追加文件是Redis 的另一种完全持久策略。它在 1.1 版中可用。

您可以在配置文件中打开 AOF:

appendonly yes

从现在开始,每次 Redis 收到更改数据集的命令(例如SET)时,它都会将其附加到 AOF。重新启动 Redis 时,它将重新播放 AOF 以重建状态。

从 Redis 7.0.0 开始,Redis 使用多部分 AOF 机制。也就是说,原始的单个 AOF 文件被拆分为基本文件(最多一个)和增量文件(可能有多个)。基本文件表示重写 AOF 时存在的数据的初始(RDB 或 AOF 格式)快照增量文件包含自上次创建基本 AOF 文件以来的增量更改。所有这些文件都放在单独的目录中,并由清单文件跟踪。

日志重写

随着写入操作的执行,AOF 会变得越来越大。例如,如果您将计数器递增 100 次,则数据集中最终会有一个包含最终值的键,但 AOF 中有 100 个条目。其中 99 个条目不需要重建当前状态。

重写是完全安全的。Redis 继续向旧文件追加内容的同时,会使用创建当前数据集所需的最少操作集生成一个全新的文件,一旦第二个文件准备就绪,Redis 就会切换这两个文件并开始向新文件追加内容。

因此,Redis 支持一项有趣的功能:它能够在后台重建 AOF,而不会中断对客户端的服务。每当您发出 时BGREWRITEAOF,Redis 都会在内存中写入重建当前数据集所需的最短命令序列。如果您在 Redis 2.2 中使用 AOF,则需要BGREWRITEAOF不时运行。因为 Redis 2.4 能够自动触发日志重写(有关更多信息,请参阅示例配置文件)。

从 Redis 7.0.0 开始,当 AOF 重写被调度时,Redis 父进程会开启一个新的增量 AOF 文件继续写入。子进程执行重写逻辑并生成新的基础 AOF。Redis 会使用一个临时的清单文件来追踪新生成的基础文件和增量文件。当它们准备就绪后,Redis 会执行一次原子替换操作来让这个临时的清单文件生效。为了避免 AOF 重写反复失败并重试时产生大量增量文件的问题,Redis 引入了 AOF 重写限制机制,确保失败的 AOF 重试的速度越来越慢。

仅附加文件的持久性如何?

您可以配置 Redis 将数据写入磁盘的次数 fsync。有三个选项:

  • appendfsync alwaysfsync每次将新命令附加到 AOF 时。非常慢,但非常安全。请注意,在执行来自多个客户端或管道的一批命令后,命令才会附加到 AOF,因此这意味着一次写入和一次 fsync(在发送回复之前)。
  • appendfsync everysecfsync每秒。速度足够快(自 2.4 版以来可能与快照一样快),如果发生灾难,您可能会丢失 1 秒的数据。
  • appendfsync no:永远不要fsync,只需将您的数据交给操作系统即可。这种方法更快,但更不安全。通常,Linux 会使用此配置每 30 秒刷新一次数据,但这取决于内核的精确调整。

建议的(也是默认的)策略是fsync每秒一次。它既快又相对安全。该always策略在实践中非常慢,但它支持组提交,因此如果有多个并行写入,Redis 将尝试执行单个fsync操作。

如果我的 AOF 被截断,我该怎么办?

服务器可能在写入 AOF 文件时崩溃,或者存储 AOF 文件的卷在写入时已满。发生这种情况时,AOF 仍包含表示数据集给定时间点版本的一致数据(使用默认 AOF fsync 策略,该版本可能最多为一秒),但 AOF 中的最后一条命令可能会被截断。Redis 的最新主要版本无论如何都能够加载 AOF,只是丢弃文件中最后一条格式不正确的命令。在这种情况下,服务器将发出如下日志:

* Reading RDB preamble from AOF file...
* Reading the remaining AOF tail...
# !!! Warning: short read while loading the AOF file !!!
# !!! Truncating the AOF at offset 439 !!!
# AOF loaded anyway because aof-load-truncated is enabled

如果需要,您可以更改默认配置以强制 Redis 在这种情况下停止,但默认配置是继续,无论文件中的最后一个命令格式是否正确,以保证重新启动后的可用性。

旧版本的 Redis 可能无法恢复,可能需要以下步骤:

  • 制作 AOF 文件的备份副本。

  • redis-check-aof使用Redis自带的工具修复原始文件:

    $ redis-check-aof --fix <filename>
    
  • 可选择使用它diff -u来检查两个文件之间的区别。

  • 使用修复的文件重新启动服务器。

如果我的 AOF 损坏了,我该怎么办?

如果 AOF 文件不只是被截断,而且中间有无效字节序列损坏,情况会变得更加复杂。Redis 将在启动时发出警告并中止:

* Reading the remaining AOF tail...
# Bad file format reading the append only file: make a backup of your AOF file, then use ./redis-check-aof --fix <filename>

最好的办法是运行该redis-check-aof实用程序,最初不带选项--fix,然后了解问题,跳转到文件中的给定偏移量,看看是否可以手动修复文件:AOF 使用与 Redis 协议相同的格式,手动修复非常简单。否则,可以让实用程序为我们修复文件,但在这种情况下,从无效部分到文件末尾的所有 AOF 部分都可能被丢弃,如果损坏恰好发生在文件的起始部分,则会导致大量数据丢失。

工作原理

日志重写使用与快照相同的写时复制技巧。它的工作原理如下:

Redis >= 7.0

  • Redis分叉,因此现在我们有一个子进程和一个父进程。

  • 子进程开始在临时文件中写入新的基础 AOF。

  • 父级会打开一个新的增量 AOF 文件来继续写入更新。如果重写失败,那么旧的基础和增量文件(如果有的话)加上这个新打开的增量文件就代表了完整的更新数据集,所以我们是安全的。

  • 当子进程完成对基础文件的重写后,父进程会收到信号,并使用新打开的增量文件和子进程生成的基础文件来构建临时清单并将其持久化。

  • 成功了!现在 Redis 对清单文件进行原子交换,以便此 AOF 重写的结果生效。Redis 还会清理旧的基础文件和任何未使用的增量文件。

Redis < 7.0

  • Redis分叉,因此现在我们有一个子进程和一个父进程。

  • 子进程开始在临时文件中写入新的 AOF。

  • 父级将所有新的更改累积在内存缓冲区中(但同时它将新的更改写入旧的仅追加文件中,因此如果重写失败,我们是安全的)。

  • 当子进程完成文件重写后,父进程会收到信号,并将内存缓冲区附加到子进程生成的文件末尾。

  • 现在 Redis 会原子地将新文件重命名为旧文件,并开始将新数据附加到新文件中。

如果我目前正在使用 dump.rdb 快照,如何切换到 AOF?

如果要在当前使用 RDB 快照的服务器中启用 AOF,则需要先在实时服务器上通过 CONFIG 命令启用 AOF 来转换数据。

重要提示:不遵循此程序(例如,仅更改配置并重新启动服务器)可能会导致数据丢失!

Redis >= 2.2

准备工作:

  • 备份最新的 dump.rdb 文件。
  • 将此备份转移到安全的地方。

在实时数据库上切换到 AOF:

  • 启用 AOF:redis-cli config set appendonly yes
  • 选择性地禁用 RDB:redis-cli config set save ""
  • 确保写入内容正确附加到仅附加文件。
  • 重要提示:更新您的redis.conf(可能通过CONFIG REWRITE)并确保它与上面的配置相匹配。如果您忘记了此步骤,则在重新启动服务器时,配置更改将丢失,服务器将使用旧配置重新启动,从而导致数据丢失。

下次重新启动服务器时:

  • 在重启服务器之前,等待 AOF 重写完成数据持久化。您可以通过观察INFO persistence、等待aof_rewrite_in_progress和以及验证 来aof_rewrite_scheduled完成此操作。0aof_last_bgrewrite_statusok
  • 重新启动服务器后,检查数据库是否包含与之前相同数量的键。

Redis 2.0

  • 备份最新的 dump.rdb 文件。
  • 将此备份转移到安全的地方。
  • 停止对数据库的所有写入!
  • 发出redis-cli BGREWRITEAOF。这将创建仅附加文件。
  • 当 Redis 完成生成 AOF 转储时停止服务器。
  • 编辑 redis.conf 结束启用仅附加文件持久性。
  • 重新启动服务器。
  • 确保您的数据库包含与切换前相同数量的键。
  • 确保写入内容正确附加到仅附加文件。

AOF 与 RDB 持久化之间的交互

Redis >= 2.4 确保避免在 RDB 快照操作正在进行时触发 AOF 重写,或者允许BGSAVEAOF 重写进行一段时间。这可以防止两个 Redis 后台进程同时进行繁重的磁盘 I/O。

当快照正在进行中并且用户明确请求使用BGREWRITEAOF服务器进行日志重写操作时,将回复一个 OK 状态代码,告知用户操作已安排,并且重写将在快照完成后开始。

如果同时启用 AOF 和 RDB 持久性并且 Redis 重新启动,则 AOF 文件将用于重建原始数据集,因为它保证是最完整的。

备份 Redis 数据

在开始本节之前,请务必阅读以下句子:确保备份数据库。磁盘损坏、云中的实例消失等等:没有备份意味着数据消失在 /dev/null 中的风险巨大。

Redis 非常适合数据备份,因为您可以在数据库运行时复制 RDB 文件:RDB 一旦生成就不会被修改,并且在生成时会使用临时名称,并且仅当新的快照完成时才使用 rename(2) 以原子方式重命名为最终目的地。

这意味着在服务器运行时复制 RDB 文件是完全安全的。我们建议:

  • 在您的服务器中创建一个 cron 作业,在一个目录中创建 RDB 文件的每小时快照,并在不同的目录中创建每日快照。
  • 每次运行 cron 脚本时,请务必调用命令find以确保删除过旧的快照:例如,您可以对最近 48 小时进行每小时快照,对一两个月进行每日快照。确保使用日期和时间信息命名快照。
  • 每天至少一次确保将 RDB 快照传输到数据中心之外,或者至少传输到运行 Redis 实例的物理机器之外。

备份 AOF 持久性

如果您运行的 Redis 实例仅启用了 AOF 持久性,您仍然可以执行备份。自 Redis 7.0.0 起,AOF 文件被拆分为多个文件,这些文件位于由配置确定的单个目录中appenddirname。在正常操作期间,您只需复制/tar 此目录中的文件即可实现备份。但是,如果在重写期间完成此操作则可能会得到无效的备份。要解决此问题,您必须在备份期间禁用 AOF 重写:

  1. 使用关闭自动重写确保在此期间 不要手动启动重写(使用)。
    CONFIG SET auto-aof-rewrite-percentage 0
    BGREWRITEAOF
  2. 检查当前没有正在进行的重写, 并且验证是否为 0。如果是 1,那么您需要等待重写完成。
    INFO persistence
    aof_rewrite_in_progress
  3. 现在您可以安全地复制目录中的文件appenddirname
  4. 完成后重新启用重写:
    CONFIG SET auto-aof-rewrite-percentage <prev-value>

注意:如果要尽量减少 AOF 重写被禁用的​​时间,您可以创建指向文件的硬链接appenddirname(在上面的步骤 3 中),然后在创建硬链接后重新启用重写(步骤 4)。现在您可以复制/tar 硬链接并在完成后删除它们。这样做之所以有效,是因为 Redis 保证它只附加到此目录中的文件,或者在必要时完全替换它们,因此内容在任何给定时间点都应该是一致的。

注意:如果您想处理备份期间服务器重启的情况,并确保重启后不会自动启动重写,您可以更改上面的步骤 1,以便通过 保留更新的配置CONFIG REWRITE。只需确保在完成后重新启用自动重写(步骤 4)并将其与另一个 一起保留即可CONFIG REWRITE

在 7.0.0 版本之前,备份 AOF 文件只需复制 aof 文件即可(就像备份 RDB 快照一样)。文件可能缺少最后部分,但 Redis 仍将能够加载它(请参阅前面关于截断 AOF 文件的部分)。

灾难恢复

Redis 环境中的灾难恢复与备份基本相同,但能够将这些备份传输到许多不同的外部数据中心。这样,即使发生一些灾难性事件影响 Redis 运行和生成快照的主数据中心,数据也能得到保护。

我们将回顾最有趣且成本不太高的灾难恢复技术。

  • Amazon S3 和其他类似服务是实施灾难恢复系统的好方法。只需将您的每日或每小时 RDB 快照以加密形式传输到 S3 即可。您可以使用gpg -c(对称加密模式)加密数据。确保将您的密码存储在许多不同的安全位置(例如,将副本提供给组织中最重要的人员)。建议使用多种存储服务以提高数据安全性。
  • 使用 SCP(SSH 的一部分)将快照传输到远程服务器。这是一个相当简单且安全的路线:在离您很远的地方获取一个小型 VPS,在那里安装 ssh,并生成一个没有密码的 ssh 客户端密钥,然后将其添加到authorized_keys小型 VPS 的文件中。您已准备好以自动化方式传输备份。为了获得最佳效果,至少在两个不同的提供商处获取两个 VPS。

重要的是要明白,如果实施不当,该系统很容易失败。至少,要确保在传输完成后,您能够验证文件大小(应与您复制的文件的大小相匹配),并且如果您使用的是 VPS,则可能还要验证 SHA1 摘要。

如果由于某种原因新备份的传输无法进行,您还需要某种独立的警报系统。

给此页面评分
返回顶部 ↑