Redis 持久性

Redis 如何将数据写入磁盘

持久性是指将数据写入持久存储(例如固态硬盘 (SSD))的过程。Redis 提供了一系列持久性选项。这些选项包括

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

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

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

RDB 优势

  • RDB 是一个非常紧凑的单文件时间点表示,用于表示 Redis 数据。RDB 文件非常适合备份。例如,您可能希望每小时存档一次 RDB 文件,以备最近 24 小时使用,并保存 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 能够在后台自动重写 AOF。重写是完全安全的,因为在 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 配置为在数据集中至少有 M 处更改时每 N 秒保存一次数据集,或者您可以手动调用 SAVEBGSAVE 命令。

例如,此配置将使 Redis 在至少 1000 个键发生更改时每 60 秒自动将数据集转储到磁盘

save 60 1000

此策略称为快照

工作原理

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

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

  • 子进程开始将数据集写入临时 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 always:每次将新命令追加到 AOF 时都会执行 fsync。非常非常慢,非常安全。请注意,在执行来自多个客户端或管道的一批命令后,命令会追加到 AOF,这意味着单次写入和单次 fsync(在发送答复之前)。
  • appendfsync everysec:每秒执行一次 fsync。足够快(自版本 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 附带的 redis-check-aof 工具修复原始文件

    $ 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 fork,所以现在我们有一个子进程和一个父进程。

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

  • 父进程打开一个新的增量 AOF 文件以继续写入更新。如果重写失败,则旧的基本文件和增量文件(如果有)加上这个新打开的增量文件表示完整的更新数据集,所以我们是安全的。

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

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

Redis < 7.0

  • Redis fork,所以现在我们有一个子进程和一个父进程。

  • 子进程开始在临时文件中写入新的 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_progressaof_rewrite_scheduled0,并验证 aof_last_bgrewrite_statusok
  • 在重新启动服务器后,检查您的数据库是否包含与之前相同的键数。

Redis 2.0

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

AOF 和 RDB 持久性之间的交互

Redis >= 2.4 确保在 RDB 快照操作正在进行时避免触发 AOF 重写,或在 AOF 重写正在进行时允许 BGSAVE。这可防止两个 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 持久性

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

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

注意:如果要最大程度地减少禁用 AOF 重写的时间,可以在 appenddirname 中的文件(在上述步骤 3 中)创建硬链接,然后在创建硬链接后重新启用重写(步骤 4)。现在,可以复制/打包硬链接,并在完成后将其删除。这样做是因为 Redis 保证它只会追加到此目录中的文件,或在必要时完全替换它们,因此内容在任何给定时间点都应该是保持一致的。

注意:如果要处理备份期间服务器重新启动的情况,并确保重新启动后不会自动启动重写,可以将上述步骤 1 更改为通过 CONFIG REWRITE 来持久化更新的配置。在完成后,只需重新启用自动重写(步骤 4)并使用另一个 CONFIG REWRITE 来持久化它。

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

灾难恢复

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

我们将回顾一些最有趣的灾难恢复技术,这些技术成本不高。

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

了解到如果未以正确的方式实施,此系统很容易失败非常重要。至少要确保在传输完成后,你能够验证文件大小(应与你复制的文件大小匹配),如果使用 VPS,则可能还要验证 SHA1 摘要。

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

评价此页面