持久化
KeyDB 提供一系列不同的持久化选项
- RDB (Redis 数据库):RDB 持久化在指定的时间间隔内对您的数据集执行时间点快照。
- AOF (仅追加文件):AOF 持久化记录服务器接收到的每个写操作,这些操作将在服务器启动时再次执行,以重建原始数据集。命令使用与 KeyDB 协议本身相同的格式以仅追加的方式记录。当日志文件变得过大时,KeyDB 能够在后台重写该日志。
- 无持久化:如果您希望数据仅在服务器运行时存在,可以完全禁用持久化。
- RDB + AOF:可以在同一个实例中结合使用 AOF 和 RDB。请注意,在这种情况下,当 KeyDB 重启时,将使用 AOF 文件来重建原始数据集,因为它可以保证是最完整的。
最重要的是要理解 RDB 和 AOF 持久化之间的不同权衡。让我们从 RDB 开始。
#
RDB 的优势- RDB 是 KeyDB 数据的一个非常紧凑的单文件时间点表示。RDB 文件非常适合用于备份。例如,您可能希望每小时归档过去 24 小时的 RDB 文件,并且每天保存一个 RDB 快照,持续 30 天。这使您在发生灾难时可以轻松恢复不同版本的数据集。
- RDB 非常适用于灾难恢复,它是一个单一的紧凑文件,可以传输到远程数据中心,或上传到 Amazon S3(可以加密)。
- RDB 最大化了 KeyDB 的性能,因为 KeyDB 父进程为了持久化所需要做的唯一工作就是派生一个子进程来完成所有其余工作。父实例永远不会执行磁盘 I/O 或类似操作。
- 与 AOF 相比,RDB 允许在处理大数据集时更快地重启。
- 在副本上,RDB 支持在重启和故障转移后进行部分重同步。
#
RDB 的劣势- 如果您需要最大限度地减少 KeyDB 停止工作(例如断电后)时数据丢失的风险,RDB 并不是一个好的选择。您可以配置不同的*保存点*来生成 RDB(例如,在至少五分钟且数据集有 100 次写入后,但您可以设置多个保存点)。然而,您通常会每五分钟或更长时间创建一个 RDB 快照,因此如果 KeyDB 因任何原因未能正常关闭而停止工作,您应该准备好丢失最近几分钟的数据。
- RDB 需要频繁地 fork() 以便使用子进程在磁盘上进行持久化。如果数据集很大,fork() 可能会非常耗时,并可能导致 KeyDB 停止为客户端服务几毫秒甚至一秒钟(如果数据集非常大且 CPU 性能不佳)。AOF 也需要 fork(),但您可以调整重写日志的频率,而不会对持久性造成任何影响。
#
AOF 的优势- 使用 AOF 的 KeyDB 更具持久性:您可以有不同的 fsync 策略:完全不 fsync、每秒 fsync、每个查询 fsync。在默认的每秒 fsync 策略下,写入性能仍然很好(fsync 由后台线程执行,主线程会尽力在没有 fsync 进行时执行写入),但您最多只会丢失一秒钟的写入数据。
- AOF 日志是一个仅追加的日志,因此在断电时没有寻道问题,也不会出现损坏问题。即使由于某种原因(磁盘已满或其他原因)日志以一个未写完的命令结尾,keydb-check-aof 工具也能轻松修复它。
- 当 AOF 文件变得过大时,KeyDB 能够自动在后台重写它。重写过程是完全安全的,因为在 KeyDB 继续向旧文件追加内容的同时,会生成一个全新的文件,该文件包含创建当前数据集所需的最少操作集。一旦这个新文件准备就绪,KeyDB 就会切换这两个文件,并开始向新文件追加内容。
- AOF 包含一个易于理解和解析的格式,按顺序记录了所有操作。您甚至可以轻松地导出 AOF 文件。例如,即使您不小心使用了 `FLUSHALL` 命令清空了所有数据,只要在此期间没有进行日志重写,您仍然可以通过停止服务器、删除最后一个命令并重新启动 KeyDB 来保存您的数据集。
#
AOF 的劣势- 对于相同的数据集,AOF 文件通常比等效的 RDB 文件更大。
- 根据具体的 fsync 策略,AOF 可能比 RDB 慢。通常,当 fsync 设置为*每秒*时,性能仍然非常高;而禁用 fsync 时,即使在高负载下,其速度也应与 RDB 完全相同。尽管如此,即使在巨大的写入负载下,RDB 也能提供关于最大延迟的更多保证。
- 在过去,我们曾遇到过特定命令(例如涉及像 `BRPOPLPUSH` 这样的阻塞命令)中罕见的错误,导致生成的 AOF 在重新加载时无法精确地重现相同的数据集。这些错误很少见,我们在测试套件中有测试,可以自动创建随机的复杂数据集并重新加载它们,以检查一切是否正常。然而,这类错误在使用 RDB 持久化时几乎不可能发生。为了更清楚地说明这一点:KeyDB AOF 通过增量更新现有状态来工作,就像 MySQL 或 MongoDB 一样,而 RDB 快照则是一次又一次地从头开始创建所有内容,这在概念上更稳健。但是——1) 应该注意的是,每当 KeyDB 重写 AOF 时,它都是从数据集中包含的实际数据从头开始重新创建的,这使得它比一个始终追加的 AOF 文件(或通过读取旧 AOF 而不是读取内存数据来重写的文件)更能抵抗错误。2) 我们从未收到过任何用户报告说在实际应用中检测到 AOF 损坏。
#
好吧,那我应该用哪个?一般的建议是,如果您想要的数据安全级别与 PostgreSQL 所能提供的相媲美,您应该同时使用这两种持久化方法。
如果您非常关心您的数据,但仍然可以容忍在发生灾难时丢失几分钟的数据,您可以只使用 RDB。
有许多用户单独使用 AOF,但我们不鼓励这样做,因为不时地拥有一个 RDB 快照对于进行数据库备份、加快重启速度以及在 AOF 引擎出现错误时都是一个好主意。
注意:由于所有这些原因,我们很可能在未来(长期计划)将 AOF 和 RDB 统一为单一的持久化模型。
以下各节将详细说明这两种持久化模型的更多细节。
#
快照默认情况下,KeyDB 将数据集的快照保存在磁盘上,文件名为 `dump.rdb` 的二进制文件。您可以配置 KeyDB,让它在数据集至少有 M 个更改时每 N 秒保存一次数据集,或者您可以手动调用 `SAVE` 或 `BGSAVE` 命令。
例如,这个配置将使 KeyDB 在至少有 1000 个键发生更改时,每 60 秒自动将数据集转储到磁盘:
这种策略被称为*快照*。
#
工作原理每当 KeyDB 需要将数据集转储到磁盘时,会发生以下情况:
KeyDB forks。我们现在有了一个子进程和一个父进程。
子进程开始将数据集写入一个临时的 RDB 文件。
当子进程完成写入新的 RDB 文件后,它会替换掉旧的文件。
这种方法让 KeyDB 能够受益于写时复制(copy-on-write)语义。
#
仅追加文件快照的持久性不是很强。如果运行 KeyDB 的计算机停止运行、电源线出现故障,或者您不小心 `kill -9` 了您的实例,那么写入 KeyDB 的最新数据将会丢失。虽然这对于某些应用程序来说可能不是大问题,但有些用例需要完全的持久性,而在这些情况下,KeyDB 以前可能不是一个可行的选择。
*仅追加文件*是 KeyDB 的一种替代方案,一种完全持久的策略。
您可以在配置文件中开启 AOF:
从现在开始,每当 KeyDB 收到一个改变数据集的命令(例如 `SET`),它就会将该命令追加到 AOF。当您重启 KeyDB 时,它会重新执行 AOF 来重建状态。
#
日志重写正如您可以猜到的,随着写操作的执行,AOF 文件会越来越大。例如,如果您将一个计数器递增 100 次,最终您的数据集中只有一个键包含最终值,但在您的 AOF 中却有 100 个条目。其中 99 个条目对于重建当前状态来说是不必要的。
因此 KeyDB 支持一个有趣的特性:它能够在不中断对客户端服务的情况下,在后台重建 AOF。无论何时您发出 `BGREWRITEAOF` 命令,KeyDB 都会写入重建当前内存中数据集所需的最短命令序列。KeyDB 能够自动触发日志重写(更多信息请参见配置文件)。
#
仅追加文件的持久性有多强?您可以配置 KeyDB 将数据 `fsync` 到磁盘的频率。有三个选项:
appendfsync always
:每当新命令被追加到 AOF 时都执行 `fsync`。非常非常慢,但非常安全。请注意,命令是在执行了来自多个客户端或一个管道的一批命令后才追加到 AOF 的,所以这意味着一次写入和一次 fsync(在发送回复之前)。appendfsync everysec
:每秒 `fsync` 一次。速度足够快,如果发生灾难,您可能会丢失 1 秒的数据。appendfsync no
:从不 `fsync`,把数据交给操作系统处理。这是最快但最不安全的方法。通常情况下,Linux 在这种配置下会每 30 秒刷新一次数据,但这取决于内核的具体调优。
建议的(也是默认的)策略是每秒 `fsync` 一次。它既非常快又相当安全。`always` 策略在实践中非常慢,但它支持组提交,所以如果有多个并行写入,KeyDB 会尝试执行单次 `fsync` 操作。
#
如果我的 AOF 文件被截断了,我该怎么办?有可能服务器在写入 AOF 文件时崩溃,或者存储 AOF 文件的卷在写入时已满。当这种情况发生时,AOF 仍然包含代表某个时间点版本的一致数据(在默认的 AOF fsync 策略下,这可能是一秒钟前的数据),但 AOF 中的最后一个命令可能会被截断。最新主要版本的 KeyDB 仍然可以加载 AOF,只是会丢弃文件中最后一个格式不正确的命令。在这种情况下,服务器会发出如下日志:
如果您希望,可以更改默认配置以强制 KeyDB 在这种情况下停止,但默认配置是继续运行,不管文件中的最后一个命令格式是否正确,以保证重启后的可用性。
旧版本的 KeyDB 可能无法恢复,并且可能需要以下步骤:
为您的 AOF 文件创建一个备份副本。
使用 KeyDB 附带的 `keydb-check-aof` 工具修复原始文件:
(可选)使用 `diff -u` 来检查两个文件之间的差异。
用修复后的文件重启服务器。
#
如果我的 AOF 文件损坏了,我该怎么办?如果 AOF 文件不只是被截断,而是在中间被无效的字节序列损坏,情况就更复杂了。KeyDB 会在启动时报错并中止:
最好的做法是运行 `keydb-check-aof` 工具,开始时不要带 `--fix` 选项,然后了解问题,跳转到文件中的指定偏移量,看看是否可以手动修复文件:AOF 使用与 KeyDB 协议相同的格式,手动修复相当简单。否则,可以由工具为我们修复文件,但在这种情况下,从无效部分到文件末尾的所有 AOF 部分都可能被丢弃,如果损坏发生在文件的初始部分,这可能导致大量数据丢失。
#
工作原理日志重写使用了与快照相同的写时复制技巧。工作原理如下:
KeyDB forks,所以现在我们有了一个子进程和一个父进程。
子进程开始在一个临时文件中写入新的 AOF。
父进程在一个内存缓冲区中累积所有新的更改(但同时它也会将新的更改写入旧的仅追加文件中,所以如果重写失败,我们是安全的)。
当子进程完成文件重写后,父进程会收到一个信号,并将内存缓冲区追加到子进程生成的文件末尾。
大功告成!现在 KeyDB 原子地将旧文件重命名为新文件,并开始向新文件追加新数据。
#
如果我当前正在使用 dump.rdb 快照,如何切换到 AOF?- 备份您最新的 dump.rdb 文件。
- 将此备份转移到一个安全的地方。
- 发出以下两个命令:
- keydb-cli config set appendonly yes
- keydb-cli config set save ""
- 确保您的数据库包含的键数量与之前相同。
- 确保写入操作被正确地追加到仅追加文件中。
第一个 CONFIG 命令启用了仅追加文件。为此,KeyDB 将会阻塞以生成初始转储,然后会打开文件进行写入,并开始追加所有后续的写查询。
第二个 CONFIG 命令用于关闭快照持久化。这是可选的,如果您愿意,可以同时启用两种持久化方法。
重要提示:记得编辑您的 KeyDB.conf 文件以开启 AOF,否则当您重启服务器时,配置更改将会丢失,服务器将以旧的配置重新启动。
#
AOF 和 RDB 持久化之间的交互KeyDB 确保在 RDB 快照操作正在进行时避免触发 AOF 重写,或者在 AOF 重写正在进行时允许 `BGSAVE`。这可以防止两个 KeyDB 后台进程同时进行繁重的磁盘 I/O 操作。
当快照正在进行中,且用户使用 `BGREWRITEAOF` 明确请求日志重写操作时,服务器将回复一个 OK 状态码,告知用户操作已被安排,并将在快照完成后开始重写。
如果同时启用了 AOF 和 RDB 持久化,并且 KeyDB 重启,AOF 文件将被用来重建原始数据集,因为它可以保证是最完整的。
#
备份 KeyDB 数据在开始本节之前,请务必阅读以下句子:确保备份您的数据库。磁盘会损坏,云中的实例会消失等等:没有备份意味着数据消失在 /dev/null 中的巨大风险。
KeyDB 对数据备份非常友好,因为您可以在数据库运行时复制 RDB 文件:RDB 一旦生成就不会被修改,并且在生成过程中它会使用一个临时名称,只有在新快照完成后才会使用 rename(2) 原子地重命名为其最终目标。
这意味着在服务器运行时复制 RDB 文件是完全安全的。我们建议如下:
- 在您的服务器上创建一个 cron 任务,在一个目录中创建 RDB 文件的每小时快照,在另一个目录中创建每日快照。
- 每次 cron 脚本运行时,确保调用 `find` 命令来删除过旧的快照:例如,您可以保留最近 48 小时的每小时快照,以及一两个月的每日快照。确保用日期和时间信息命名快照。
- 每天至少一次,确保将 RDB 快照传输到*数据中心之外*或至少是*运行 KeyDB 实例的物理机之外*。
如果您运行一个只启用了 AOF 持久化的 KeyDB 实例,您仍然可以复制 AOF 文件来创建备份。该文件可能缺少最后一部分,但 KeyDB 仍然能够加载它(请参见前文中关于被截断的 AOF 文件的部分)。
#
灾难恢复在 KeyDB 的背景下,灾难恢复基本上与备份是同一回事,只是增加了将这些备份传输到多个不同的外部数据中心的能力。这样,即使在影响 KeyDB 运行和产生快照的主数据中心的某些灾难性事件中,数据也能得到保障。
由于许多 KeyDB 用户都处于初创阶段,因此没有太多钱可以花费,我们将回顾一些成本不高的最有趣的灾难恢复技术。
- Amazon S3 和其他类似服务是实现您的灾难恢复系统的好方法。只需将您的每日或每小时的 RDB 快照以加密形式传输到 S3。您可以使用 `gpg -c`(对称加密模式)来加密您的数据。请确保将您的密码存储在多个安全的地方(例如,给您组织中最重要的几个人一份副本)。建议使用多个存储服务以提高数据安全性。
- 使用 SCP(SSH 的一部分)将您的快照传输到远程服务器。这是一条相当简单和安全的途径:在离您很远的地方租用一个小型 VPS,在那里安装 ssh,并生成一个没有密码的 ssh 客户端密钥,然后将其添加到您的小型 VPS 的 `authorized_keys` 文件中。您就可以自动传输备份了。为了获得最佳效果,请在两个不同的提供商处获取至少两个 VPS。
重要的是要理解,如果实施不当,这个系统很容易失败。至少要绝对确保在传输完成后,您能够验证文件大小(应与您复制的文件大小匹配),如果使用 VPS,可能还要验证 SHA1 摘要。
如果新备份的传输因某种原因无法正常工作,您还需要某种独立的警报系统。