持久化是指将数据写入持久性存储,例如固态硬盘 (SSD)。Valkey 提供一系列持久化选项。其中包括
- RDB (Valkey 数据库):RDB 持久化在指定间隔对您的数据集执行时间点快照。
- AOF (仅追加文件):AOF 持久化记录服务器接收到的每个写入操作。这些操作可以在服务器启动时重新播放,从而重建原始数据集。命令使用与 Valkey 协议本身相同的格式进行记录。
- 无持久化:您可以完全禁用持久化。这有时用于缓存场景。
- RDB + AOF:您也可以在同一个实例中结合使用 AOF 和 RDB。
要了解更多关于如何评估您的 Valkey 持久化策略,请继续阅读。
RDB 优点
- RDB 是 Valkey 数据非常紧凑的单文件时间点表示。RDB 文件非常适合备份。例如,您可能希望每小时归档最近 24 小时的 RDB 文件,并每天保存一个 RDB 快照,持续 30 天。这使您可以在发生灾难时轻松恢复不同版本的数据集。
- RDB 非常适合灾难恢复,它是一个紧凑的单文件,可以传输到远程数据中心或 Amazon S3(可能加密)。
- RDB 最大化 Valkey 性能,因为 Valkey 父进程为了持久化所做的唯一工作是派生一个子进程来完成所有其余工作。父进程永远不会执行磁盘 I/O 或类似操作。
- 与 AOF 相比,RDB 允许大数据集更快地重启。
- 在副本上,RDB 支持重启和故障转移后的部分重新同步。
RDB 缺点
- 如果您需要最大程度地减少 Valkey 停止工作(例如断电后)时的数据丢失可能性,RDB 则不适用。您可以配置不同的保存点来生成 RDB(例如,在至少五分钟和对数据集进行 100 次写入之后,您可以设置多个保存点)。然而,您通常每五分钟或更长时间创建一个 RDB 快照,因此如果 Valkey 因任何原因未正确关闭而停止工作,您应该准备好丢失最新几分钟的数据。
- RDB 需要经常 fork() 以使用子进程将数据持久化到磁盘。如果数据集很大,fork() 可能会很耗时,并且如果数据集非常大且 CPU 性能不佳,可能会导致 Valkey 停止为客户端服务几毫秒甚至一秒钟。AOF 也需要 fork() 但频率较低,您可以调整重写日志的频率而不会在持久性方面做出任何权衡。
AOF 优点
- 使用 AOF,Valkey 更具持久性:您可以有不同的 fsync 策略:完全不 fsync、每秒 fsync、每个查询 fsync。默认策略是每秒 fsync,写入性能仍然非常出色。fsync 是通过后台线程执行的,主线程会努力在没有 fsync 进行时执行写入,因此您只会丢失一秒钟的写入。
- AOF 日志是仅追加日志,因此没有寻道问题,也不会在断电时出现损坏问题。即使日志因某种原因(磁盘已满或其他原因)以半写入的命令结束,valkey-check-aof 工具也能轻松修复它。
- 当 AOF 文件过大时,Valkey 能够在后台自动重写 AOF。重写是完全安全的,因为当 Valkey 继续追加到旧文件时,会生成一个全新的文件,其中包含创建当前数据集所需的最少操作集,一旦这个新文件准备好,Valkey 就会切换到新文件并开始向其追加。
- AOF 包含所有操作的日志,按顺序排列,格式易于理解和解析。您甚至可以轻松导出 AOF 文件。例如,即使您不小心使用
FLUSHALL
命令清除了所有内容,只要在此期间没有对日志进行重写,您仍然可以通过停止服务器、删除最新的命令并重新启动 Valkey 来保存数据集。
AOF 缺点
- 对于相同的数据集,AOF 文件通常比等效的 RDB 文件更大。
- AOF 可能比 RDB 慢,具体取决于精确的 fsync 策略。通常,当 fsync 设置为每秒时,性能仍然非常高,并且禁用 fsync 时,即使在高负载下,其速度也应该与 RDB 完全相同。然而,即使在巨大的写入负载情况下,RDB 也能提供更多关于最大延迟的保证。
那么,我应该使用什么?
通常建议您同时使用这两种持久化方法,如果您希望获得与 PostgreSQL 类似的数据安全性。
如果您非常关心数据,但仍然可以接受在灾难发生时丢失几分钟的数据,那么您可以单独使用 RDB。
有许多用户单独使用 AOF,但我们不鼓励这样做,因为时不时地拥有 RDB 快照对于数据库备份、更快重启以及在 AOF 引擎出现 bug 时都是一个好主意。
以下部分将详细介绍这两种持久化模型。
快照
默认情况下,Valkey 将数据集快照保存到磁盘上的一个名为 dump.rdb
的二进制文件中。您可以配置 Valkey,使其在数据集中至少有 M 次更改时每 N 秒保存一次数据集,或者您可以手动调用 SAVE
或 BGSAVE
命令。
例如,此配置将使 Valkey 在至少 1000 个键更改时,每 60 秒自动将数据集转储到磁盘。
save 60 1000
此策略被称为快照。
无持久化
如果您选择不进行持久化(例如,当 Valkey 实例仅用作缓存时),这也是一种可能性。
RDB 快照默认启用。要禁用它,请将 save
配置参数设置为空字符串 ""
,并删除当前配置文件中存在的任何多余的 save
行。
save ""
或者,您也可以在 valkey-server
可执行文件上使用 --save ""
参数。
工作原理
每当 Valkey 需要将数据集转储到磁盘时,会发生以下情况:
-
Valkey 执行 fork 操作。现在我们有一个子进程和一个父进程。
-
子进程开始将数据集写入临时的 RDB 文件。
-
当子进程完成写入新的 RDB 文件后,它会替换旧文件。
此方法使 Valkey 能够受益于写时复制语义。
仅追加文件
快照不是非常持久。如果运行 Valkey 的计算机停止,电源线故障,或者您不小心 kill -9
您的实例,写入 Valkey 的最新数据将丢失。虽然这对于某些应用程序来说可能不是大问题,但存在对完全持久化有需求的用例,在这些情况下,单独使用 Valkey 快照不是一个可行的选择。
仅追加文件是 Valkey 的另一种完全持久化策略。
您可以在配置文件中开启 AOF
appendonly yes
从现在开始,每当 Valkey 收到改变数据集的命令(例如 SET
)时,它都会将其追加到 AOF。当您重新启动 Valkey 时,它将重新播放 AOF 以重建状态。
Valkey 使用多部分 AOF 机制。也就是说,原始的单个 AOF 文件被拆分为基础文件(最多一个)和增量文件(可能不止一个)。基础文件表示 AOF 重写时存在的数据的初始(RDB 或 AOF 格式)快照。增量文件包含自上次基础 AOF 文件创建以来的增量更改。所有这些文件都放在一个单独的目录中,并由一个清单文件跟踪。
日志重写
随着写入操作的执行,AOF 会变得越来越大。例如,如果您将计数器增加 100 次,您的数据集中最终只有一个键包含最终值,但您的 AOF 中有 100 个条目。其中 99 个条目对于重建当前状态来说是不必要的。
重写是完全安全的。当 Valkey 继续追加到旧文件时,会生成一个全新的文件,其中包含创建当前数据集所需的最少操作集,一旦这个新文件准备好,Valkey 就会切换到新文件并开始向其追加。
Valkey 支持一个有趣的特性:它能够在后台重建 AOF,而不会中断对客户端的服务。每当您发出 BGREWRITEAOF
命令时,Valkey 将写入重建当前内存中数据集所需的最短命令序列。Valkey 将自动触发日志重写(更多信息请参见示例配置文件)。
当 AOF 重写被调度时,Valkey 父进程会打开一个新的增量 AOF 文件以继续写入。子进程执行重写逻辑并生成一个新的基础 AOF。Valkey 将使用一个临时清单文件来跟踪新生成的基础文件和增量文件。当它们准备好时,Valkey 将执行原子替换操作,使这个临时清单文件生效。为了避免在 AOF 重写反复失败和重试的情况下创建许多增量文件的问题,Valkey 引入了 AOF 重写限制机制,以确保失败的 AOF 重写以越来越慢的速度重试。
仅追加文件的持久性如何?
您可以配置 Valkey 将数据 fsync
到磁盘的频率。有三个选项:
appendfsync always
:每次新命令追加到 AOF 时都执行fsync
。非常非常慢,非常安全。请注意,命令是在执行来自多个客户端或管道的一批命令后追加到 AOF 的,因此这意味着一次写入和一次 fsync(在发送回复之前)。appendfsync everysec
:每秒fsync
。速度足够快,如果发生灾难,您可能会丢失 1 秒的数据。appendfsync no
:永不fsync
,将数据完全交给操作系统处理。速度最快但安全性最低的方法。通常在此配置下 Linux 会每 30 秒刷新一次数据,但这取决于内核的具体调优。
建议(也是默认)的策略是每秒 fsync
。它既快速又相对安全。always
策略在实践中非常慢,但它支持组提交,因此如果有多个并行写入,Valkey 将尝试执行一次 fsync
操作。
如果我的 AOF 被截断了怎么办?
服务器在写入 AOF 文件时可能崩溃了,或者 AOF 文件所在的卷在写入时已满。发生这种情况时,AOF 仍包含表示数据集某个时间点版本的一致数据(使用默认 AOF fsync 策略,该数据可能最多旧一秒),但 AOF 中的最后一个命令可能被截断。Valkey 的最新主要版本无论如何都能加载 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
如果您愿意,可以更改默认配置以强制 Valkey 在这种情况下停止,但默认配置是无论文件中最后一个命令格式是否正确都继续,以确保重启后的可用性。
旧版本的 Valkey 可能无法恢复,并且可能需要以下步骤:
-
创建 AOF 文件的备份副本。
-
使用 Valkey 附带的
valkey-check-aof
工具修复原始文件。$ valkey-check-aof --fix <filename>
-
(可选)使用
diff -u
检查两个文件之间的差异。 -
使用修复后的文件重启服务器。
如果我的 AOF 文件损坏了怎么办?
如果 AOF 文件不仅仅是被截断,而是在中间包含无效字节序列而损坏,情况会更复杂。Valkey 在启动时会报错并中止:
* Reading the remaining AOF tail...
# Bad file format reading the append only file: make a backup of your AOF file, then use ./valkey-check-aof --fix <filename>
最好的方法是运行 valkey-check-aof
工具,首先不带 --fix
选项,然后了解问题,跳转到文件中给定的偏移量,查看是否可以手动修复文件:AOF 使用与 Valkey 协议相同的格式,手动修复相当简单。否则,可以让该工具为我们修复文件,但在那种情况下,从无效部分到文件末尾的所有 AOF 部分都可能被丢弃,如果损坏发生在文件的初始部分,则可能导致大量数据丢失。
工作原理
日志重写使用与快照相同的写时复制技巧。工作原理如下:
Valkey 多部分 AOF
-
Valkey 执行 fork 操作,因此现在我们有一个子进程和一个父进程。
-
子进程开始将新的基础 AOF 写入临时文件。
-
父进程打开一个新的增量 AOF 文件以继续写入更新。如果重写失败,旧的基础文件和增量文件(如果有)加上这个新打开的增量文件代表了完整的更新数据集,因此我们是安全的。
-
当子进程完成基础文件的重写后,父进程会收到信号,并使用新打开的增量文件和子进程生成的基础文件构建一个临时清单,并将其持久化。
-
成功!现在 Valkey 对清单文件执行原子交换,使此 AOF 重写的结果生效。Valkey 还会清理旧的基础文件和任何未使用的增量文件。
如果我目前使用 dump.rdb 快照,如何切换到 AOF?
如果您想在当前使用 RDB 快照的服务器中启用 AOF,您需要首先通过在运行中的服务器上使用 CONFIG 命令启用 AOF 来转换数据。
重要提示:不遵循此过程(例如,仅仅更改配置并重启服务器)可能会导致数据丢失!
准备工作
- 备份您最新的 dump.rdb 文件。
- 将此备份传输到安全位置。
在运行中的数据库上切换到 AOF
- 启用 AOF:
valkey-cli config set appendonly yes
- (可选)禁用 RDB:
valkey-cli config set save ""
- 确保写入正确地追加到仅追加文件。
- 重要提示:更新您的
valkey.conf
(可能通过CONFIG REWRITE
),并确保它与上述配置匹配。如果您忘记此步骤,当您重新启动服务器时,配置更改将丢失,服务器将使用旧配置重新启动,导致数据丢失。
下次重启服务器时
- 在重启服务器之前,请等待 AOF 重写完成数据持久化。您可以通过查看
INFO persistence
,等待aof_rewrite_in_progress
和aof_rewrite_scheduled
为0
,并验证aof_last_bgrewrite_status
为ok
来完成此操作。 - 重启服务器后,检查您的数据库是否包含与之前相同数量的键。
AOF 和 RDB 持久化之间的交互
Valkey 确保在 RDB 快照操作正在进行时避免触发 AOF 重写,或在 AOF 重写正在进行时允许 BGSAVE
。这可以防止两个 Valkey 后台进程同时执行繁重的磁盘 I/O。
当快照正在进行中,并且用户使用 BGREWRITEAOF
明确请求日志重写操作时,服务器将回复 OK 状态码,告诉用户该操作已安排,重写将在快照完成后开始。
如果 AOF 和 RDB 持久化都已启用,并且 Valkey 重启,将使用 AOF 文件重建原始数据集,因为它被保证是最完整的。
备份 Valkey 数据
在开始本节之前,请务必阅读以下句子:请务必备份您的数据库。磁盘会损坏,云实例会消失等等:没有备份意味着数据消失的巨大风险。
Valkey 对数据备份非常友好,因为您可以在数据库运行时复制 RDB 文件:RDB 文件一旦生成就永不修改,并且在生成过程中使用临时名称,只有当新的快照完成时,才会使用 rename(2) 原子地重命名到最终目的地。
这意味着在服务器运行时复制 RDB 文件是完全安全的。我们建议如下:
- 在您的服务器中创建一个 cron 任务,在一个目录中每小时创建 RDB 文件快照,并在另一个目录中每天创建快照。
- 每次 cron 脚本运行时,请务必调用
find
命令以确保删除过旧的快照:例如,您可以保留最近 48 小时的每小时快照,以及一两个月的每日快照。请确保使用日期和时间信息命名快照。 - 每天至少一次,请务必将 RDB 快照传输到数据中心之外,或至少运行 Valkey 实例的物理机之外。
备份 AOF 持久化
如果您运行的 Valkey 实例仅启用 AOF 持久化,您仍然可以执行备份。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 <prev-value>
注意:如果您希望最小化 AOF 重写被禁用的时间,您可以创建指向 appenddirname
目录中文件的硬链接(上述步骤 3),然后在创建硬链接后重新启用重写(步骤 4)。现在您可以复制/压缩这些硬链接并在完成后删除它们。这之所以有效,是因为 Valkey 保证它只在此目录中的文件末尾追加,或者在必要时完全替换它们,因此内容在任何给定时间点都应该是一致的。
注意:如果您希望处理备份期间服务器重启的情况,并确保重启后不会自动开始重写,您可以将上述步骤 1 更改为也通过 CONFIG REWRITE
持久化更新的配置。完成后务必重新启用自动重写(步骤 4)并使用另一个 CONFIG REWRITE
持久化。
灾难恢复
Valkey 环境中的灾难恢复基本上与备份相同,加上能够将这些备份传输到许多不同的外部数据中心。这样,即使发生影响 Valkey 运行和生成快照的主数据中心的灾难性事件,数据也能得到保障。
我们将回顾一些成本不太高的最有趣的灾难恢复技术。
- Amazon S3 和其他类似服务是实现灾难恢复系统的好方法。只需将您的每日或每小时 RDB 快照以加密形式传输到 S3。您可以使用
gpg -c
(在对称加密模式下)加密数据。请务必将密码存储在多个不同的安全位置(例如,给您组织中最重要的几个人一份副本)。建议使用多个存储服务以提高数据安全性。 - 使用 SCP(SSH 的一部分)将快照传输到远程服务器。这是一种相当简单且安全的途径:在离您很远的地方租用一个小型 VPS,在那里安装 ssh,并生成一个没有密码的 ssh 客户端密钥,然后将其添加到您的小型 VPS 的
authorized_keys
文件中。您就可以以自动化方式传输备份了。为了获得最佳效果,请在两个不同的提供商处获取至少两个 VPS。
重要的是要明白,如果实施不当,这个系统很容易失败。至少,请绝对确保在传输完成后,您能够验证文件大小(应与您复制的文件大小匹配)以及可能的 SHA1 摘要,如果您使用的是 VPS。
如果由于某种原因新备份的传输不工作,您还需要某种独立的警报系统。