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 秒保存一次数据集,或者您可以手动调用 SAVE 或 BGSAVE 命令。

例如,此配置将使 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

可以选择使用 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

最好的办法是运行 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_progress 和 aof_rewrite_scheduled 为 0,并验证 aof_last_bgrewrite_status 为 ok。

在重新启动服务器后,检查您的数据库是否包含与之前相同的键数。

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 重写

使用以下命令关闭自动重写

CONFIG SET auto-aof-rewrite-percentage 0

在此期间,确保不要手动启动重写(使用 BGREWRITEAOF)。

使用以下命令检查当前是否正在进行重写

INFO persistence

并验证 aof_rewrite_in_progress 是否为 0。如果为 1,则需要等待重写完成。

现在可以安全地复制 appenddirname 目录中的文件。

完成后重新启用重写

CONFIG SET auto-aof-rewrite-percentage

注意:如果要最大程度地减少禁用 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 摘要。

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

评价此页面

★

★

★

★

★

提交