Redis 持久化
Redis 持久化
Redis 提供了一系列不同的持久性选项:
- RDB(Redis 数据库):RDB 持久性以指定的时间间隔执行数据集的时间点快照。
- AOF(Append Only File):AOF 持久化记录服务器收到的每个写操作,在服务器启动时会再次播放,重建原始数据集。命令使用与 Redis 协议本身相同的格式以仅附加的方式记录。当日志变得太大时,Redis 能够在后台重写日志。
- 无持久性:如果您希望数据在服务器运行时一直存在,您可以完全禁用持久性。
- RDB + AOF:可以在同一个实例中组合 AOF 和 RDB。请注意,在这种情况下,当 Redis 重新启动时,AOF 文件将用于重建原始数据集,因为它保证是最完整的。
要理解的最重要的事情是 RDB 和 AOF 持久性之间的不同权衡。让我们从 RDB 开始:
RDB优势
- RDB 是 Redis 数据的非常紧凑的单文件时间点表示。RDB 文件非常适合备份。例如,您可能希望在最近 24 小时内每小时存档一次 RDB 文件,并在 30 天内每天保存一个 RDB 快照。这使您可以在发生灾难时轻松恢复不同版本的数据集。
- RDB 非常适合灾难恢复,它是一个可以传输到远程数据中心或 Amazon S3(可能已加密)的紧凑文件。
- RDB 最大限度地提高了 Redis 的性能,因为 Redis 父进程为了持久化需要做的唯一工作是派生一个将完成所有其余工作的子进程。父实例永远不会执行磁盘 I/O 或类似操作。
- 与 AOF 相比,RDB 允许更快地重新启动大数据集。
- 在副本上,RDB 支持重启和故障转移后的部分重新同步。
RDB 的缺点
- 如果您需要在 Redis 停止工作(例如断电后)时将数据丢失的可能性降至最低,那么 RDB 并不好。您可以在生成 RDB 的地方配置不同的保存点(例如,在对数据集进行至少 5 分钟和 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 文件大。
- AOF 可能比 RDB 慢,具体取决于确切的 fsync 策略。一般来说,将 fsync 设置为每秒性能仍然非常高,并且禁用 fsync 后,即使在高负载下,它也应该与 RDB 一样快。即使在写入负载巨大的情况下,RDB 仍然能够提供更多关于最大延迟的保证。
- 过去我们在特定命令中遇到过罕见的错误(例如有一个涉及阻塞命令的错误,如BRPOPLPUSH) 导致生成的 AOF 在重新加载时无法重现完全相同的数据集。这些错误很少见,我们在测试套件中进行了测试,自动创建随机复杂数据集并重新加载它们以检查一切正常。但是,使用 RDB 持久性几乎不可能出现此类错误。为了更清楚地说明这一点:Redis AOF 通过增量更新现有状态来工作,就像 MySQL 或 MongoDB 那样,而 RDB 快照一次又一次地从头开始创建所有内容,这在概念上更加健壮。但是 - 1)需要注意的是,每次Redis重写AOF时,都是从数据集中包含的实际数据开始重新创建,与始终附加的 AOF 文件(或重写读取旧 AOF 而不是读取内存中的数据)相比,对错误的抵抗力更强。2) 我们从未收到过用户关于在现实世界中检测到的 AOF 损坏的单一报告。
好的,那我应该用什么?
一般的迹象是,如果您想要与 PostgreSQL 可以提供的数据安全程度相当的数据安全性,则应该同时使用这两种持久性方法。
如果您非常关心您的数据,但在发生灾难时仍然可以忍受几分钟的数据丢失,您可以简单地单独使用 RDB。
有很多用户单独使用 AOF,但我们不鼓励它,因为不时拥有 RDB 快照对于进行数据库备份、更快地重新启动以及在 AOF 引擎中出现错误时是一个好主意。
注意:由于所有这些原因,我们很可能在未来将 AOF 和 RDB 统一为一个持久化模型(长期计划)。
以下部分将说明有关这两种持久性模型的更多细节。
快照
默认情况下,Redis 将数据集的快照保存在磁盘上的一个名为dump.rdb
. 如果数据集中至少有 M 次更改,您可以将 Redis 配置为每 N 秒保存一次数据集,或者您可以手动调用SAVE或BGSAVE命令。
例如,如果至少有 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 以重建状态。
日志重写
您可以猜到,随着写入操作的执行,AOF 变得越来越大。例如,如果您将一个计数器递增 100 次,您最终将在数据集中得到一个包含最终值的键,但在 AOF 中有 100 个条目。重建当前状态不需要这些条目中的 99 个。
所以Redis支持了一个有趣的特性:它能够在不中断对客户端的服务的情况下在后台重建AOF。每当您发出BGREWRITEAOF 时, Redis 都会写入在内存中重建当前数据集所需的最短命令序列。如果您在 Redis 2.2 中使用 AOF,则需要不时运行BGREWRITEAOF。Redis 2.4 能够自动触发日志重写(更多信息请参见 2.4 示例配置文件)。
仅追加文件的持久性如何?
您可以配置 Redis 将 fsync
数据存储在磁盘上的次数。共有三个选项:
appendfsync always
:fsync
每次将新命令附加到 AOF 时。非常非常缓慢,非常安全。请注意,在执行来自多个客户端或管道的一批命令之后,这些命令会附加到 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-check-aof
Redis附带的工具修复原始文件:$ 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 <filename>
最好的办法是运行该redis-check-aof
实用程序,最初没有--fix
选项,然后了解问题,在文件中给定的偏移处跳转,看看是否可以手动修复文件:AOF 使用相同的格式Redis 协议,手动修复非常简单。否则有可能让实用程序为我们修复文件,但在这种情况下,从无效部分到文件末尾的所有 AOF 部分可能会被丢弃,如果损坏发生,将导致大量数据丢失在文件的初始部分。
这个怎么运作
日志重写使用已用于快照的相同的写时复制技巧。这是它的工作原理:
-
Redis fork,所以现在我们有一个子进程和一个父进程。
-
孩子开始在临时文件中写入新的 AOF。
-
父级在内存缓冲区中累积所有新更改(但同时它将新更改写入旧的仅附加文件中,因此如果重写失败,我们是安全的)。
-
当子进程完成重写文件时,父进程收到一个信号,并将内存缓冲区附加到子进程生成的文件的末尾。
-
利润!现在 Redis 原子地将旧文件重命名为新文件,并开始将新数据附加到新文件中。
如果我当前正在使用 dump.rdb 快照,如何切换到 AOF?
在 Redis 2.0 和 Redis 2.2 中有一个不同的过程来执行此操作,因为您可以猜到它在 Redis 2.2 中更简单,并且根本不需要重新启动。
Redis >= 2.2
- 备份最新的 dump.rdb 文件。
- 将此备份转移到安全的地方。
- 发出以下两个命令:
- redis-cli 配置集 appendonly 是
- redis-cli 配置集保存“”
- 确保您的数据库包含与其包含的相同数量的键。
- 确保写入正确附加到仅附加文件。
第一个 CONFIG 命令启用仅附加文件。为此,Redis 将阻塞以生成初始转储,然后将打开文件进行写入,并开始追加所有下一个写入查询。
第二个 CONFIG 命令用于关闭快照持久性。这是可选的,如果您愿意,可以启用两种持久性方法。
重要:记得编辑你的redis.conf 开启AOF,否则当你重启服务器时,配置更改会丢失,服务器会以旧配置重新启动。
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 持久性的情况下运行 Redis 实例,您仍然可以复制 AOF 以创建备份。该文件可能缺少最后一部分,但 Redis 仍然可以加载它(请参阅前面关于截断 AOF 文件的部分)。
灾难恢复
Redis 上下文中的灾难恢复与备份基本相同,并且能够在许多不同的外部数据中心传输这些备份。通过这种方式,即使在影响 Redis 运行并生成其快照的主数据中心的某些灾难性事件的情况下,数据也能得到保护。
由于许多 Redis 用户处于启动阶段,因此没有足够的钱可以花,因此我们将回顾最有趣的灾难恢复技术,并且成本不会太高。
- Amazon S3 和其他类似服务是实施灾难恢复系统的好方法。只需以加密形式将您的每日或每小时 RDB 快照传输到 S3。您可以使用
gpg -c
(在对称加密模式下)加密您的数据。确保将您的密码存储在许多不同的安全位置(例如,将副本提供给组织中最重要的人)。建议使用多个存储服务以提高数据安全性。 - 使用 SCP(SSH 的一部分)将您的快照传输到远程服务器。这是一个相当简单和安全的路线:在离你很远的地方找一个小VPS,在那里安装ssh,然后生成一个没有密码的ssh客户端密钥,然后将其添加
authorized_keys
到你的小VPS的文件中。您已准备好以自动方式传输备份。在两个不同的提供商处至少获得两个 VPS 以获得最佳效果。
如果没有以正确的方式实施,这个系统很容易失败,理解这一点很重要。至少确保在传输完成后您能够验证文件大小(应该与您复制的文件匹配),如果您使用的是 VPS,则可能还可以验证 SHA1 摘要。
如果由于某种原因无法传输新备份,您还需要某种独立的警报系统。