Redis持久化

Redis提供了一系列不同的持久化选项:

  • RDB持久化以指定的时间间隔执行数据集的时间点快照(point-in-time snapshots)。
  • AOF持久化记录服务器接收到的每个写入操作,这些操作将在服务器启动时再次播放,重建原始数据集。命令的记录格式与Redis协议本身的格式相同,以追加的方式记录。Redis能够在日志太大时在后台重写它。
  • 如果您仅仅想让数据在服务器运行期间一直存在,那么您可以完全禁用持久化(persistance)。
  • 可以在同一个Redis实例中组合AOF和RDB。注意,在这种情况下,当Redis重新启动时,AOF文件将用于重建原始数据集,因为它保证是最完整的。

最重要的事情是RDB与AOF持久性之间的不同权衡。让我们从RDB开始:

RDB优势

  • RDB是Redis数据的一个非常紧凑的单文件时间点表示。RDB文件非常适合备份。例如,您可能希望在最近24小时内每小时存档一次RDB文件,并在30天内每天保存一个RDB快照。这允许您在发生灾难时轻松恢复数据集的不同版本。
  • RDB非常适合灾难恢复,它是一个可以传输到远程数据中心或AmazonS3(可能是加密的)的压缩文件。
  • RDB使Redis的性能最大化,因为Redis父进程要持久化只需要派生一个子进程来完成其余的工作。父实例永远不会执行磁盘I/O或类似操作。
  • 与AOF相比,数据量很大的时候RDB可以更快地重新启动。

RDB缺点

  • 如果您需要在Redis停止工作的情况下(例如在断电之后),您需要将数据丢失的可能性降到最低,那么RDB是不好的。您通常每五分钟或更长时间创建一个RDB快照(snapshot),因此,如果Redis由于任何原因没有正确关闭而停止工作,您应该准备好丢失最近几分钟的数据
  • RDB经常需要fork()才能使用子进程在磁盘上持久化。如果数据集很大,Fork()可能很耗时,如果数据集非常大,CPU性能不好,可能会导致Redis停止为客户机服务几毫秒甚至一秒钟。AOF也需要fork(),但是您可以调整重写日志的频率,而不需要在持久化上做任何权衡。

AOF优势

  • 使用AOF Redis要持久得多:可以有不同的fsync策略:禁止同步(no fsync)每秒同步一次(fsync every second)每次查询都同步(fsync every query)。在默认策略fsync every second的情况下,写性能仍然很好(fsync是使用后台线程执行的,当没有fsync进行时,主线程将努力执行写操作),但是您只能丢失1秒的写操作
  • AOF日志是一个只附加的日志,因此如果断电,就不会出现查找或损坏问题。即使日志由于某种原因(磁盘已满或其他原因)以半写的命令结束,redis check aof工具也可以轻松地修复它。
  • 当AOF太大时,Redis能够在后台自动重写AOF。重写是完全安全的,因为当Redis继续附加到旧文件时,一个全新的文件会生成,只需创建当前数据集所需的最少操作集,一旦第二个文件就绪,Redis就会切换这两个文件并开始附加到新文件中。
  • AOF以易于理解和解析的格式包含所有操作的日志。您甚至可以轻松导出AOF文件。例如,即使您使用FLUSHALL命令刷新了所有内容以发现错误,但是如果在此期间未执行日志重写,您仍然可以保存数据集,只需停止服务器,删除最新命令并再次重新启动Redis。

AOF缺点

  • AOF文件通常比相同数据集的等效RDB文件大。
  • 根据具体的fsync策略,AOF可能比RDB慢。通常,fsync设置为fsync every second性能仍然非常高,no fsync后,即使在高负载下,它也应该与RDB一样快。尽管如此,RDB仍然能够提供更多关于最大延迟的保证,即使是在巨大的写负载的情况下。
  • 过去,我们在特定命令中遇到过罕见的错误(例如,其中有一个涉及阻止命令,例如BRPOPLPUSH),导致生成的AOF在重新加载时无法完全重现相同的数据集。这些错误很少见,我们在测试套件中进行了测试,自动创建了随机的复杂数据集,然后重新加载它们以检查一切是否正常。但是,对于RDB持久性来说,这类错误几乎是不可能的。为了更清楚地说明这一点:Redis AOF通过增量更新现有状态来工作,就像MySQL或MongoDB一样,而RDB快照一次又一次地创建所有内容,从概念上讲更健壮。但是:
    • 应当注意,每次Redis重写AOF时,都会从数据集中包含的实际数据的开头重新创建AOF,与始终添加AOF文件相比,对错误的抵抗力更强(或一次重写以读取旧的AOF而不是读取内存中的数据)
    • 我们从未收到过来自用户的关于真实环境中检测到的AOF损坏的报告。

好吧,那我该用什么呢?

  • 一般情况下,如果您希望与PostgreSQL提供的数据安全程度相当,那么应该使用这两种持久化方法。
  • 如果您非常关心自己的数据,但在发生灾难时仍然可以忍受几分钟的数据丢失,那么您可以简单地单独使用RDB。

有很多用户单独使用AOF,但我们不建议这样做,因为时不时的有RDB快照是进行数据库备份,加快重启速度以及AOF引擎中出现错误的情况下。

注意:由于所有这些原因,我们将来很可能会将AOF和RDB统一到一个单一的持久化模型中(长期计划)。

下面几节将详细说明这两个持久化模型。

1、快照(Snapshotting)

默认情况下,Redis将数据集的快照保存在磁盘上的一个名为dump.rdb. 如果数据集中至少有M个更改,可以配置Redis使其每隔N秒保存一次 数据集,或者可以手动调用SAVEBGSAVE命令。

例如,此配置将使Redis每60秒自动将 数据集转储到磁盘,如果至少更改了1000个keys:

save 60 1000

这种策略被称为快照(snapshotting).

工作原理

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

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

  • 子对象开始将数据集写入临时RDB文件。

  • 当子对象写完新的RDB文件后,它将替换旧的RDB文件。

2、仅附加文件(Append-only file)

快照不是很安全。如果运行Redis的计算机停止运行,电源线出现故障,或者您意外地 kill -9您的实例,在Redis上写入的最新数据将丢失,Redis不是一个可行的选择。

这个仅附加文件(Append-only file)是 Redis的另一种完全持久的策略。它在版本1.1中可用。

您可以在配置文件中打开AOF:

appendonly yes

从现在起,每次Redis收到更改数据集的命令(例如。SET)它将把它附加到AOF。重新启动 Redis时,它将重新播放AOF以重建状态。

日志重写

正如您所猜测的,随着写操作的执行,AOF变得越来越大。例如,如果您将一个计数器递增100倍,您将在数据集中得到一个包含最终值的键,但在AOF中只有100个条目。其中99个条目不需要重建当前状态。

因此Redis支持一个有趣的特性:它能够在后台重建AOF,而不会中断对客户端的服务。当你执行BGREWRITEAOF,Redis将编写在内存中重建当前数据集所需的最短命令序列。如果你在Redis2.2中使用AOF,你需要时不时的运行BGREWRITEAOF。Redis 2.4能够自动触发日志重写。

仅附加文件的持久性如何?

您可以配置Redis将磁盘上的数据同步多少次。有三种选择:

  • 始终同步(appendfsync always):每次新命令被附加到AOF时。非常非常安全。
  • 每秒同步一次(appendfsync everysec):足够快(在2.4中可能与快照一样快),如果发生灾难,您可能会丢失1秒的数据。
  • 从不同步(appendfsync no):从不同步,只需将数据交给操作系统即可。更快更不安全的方法。通常Linux使用这个配置每隔30秒刷新一次数据,但这取决于内核的精确调整。

建议(和默认)策略是每一秒同步一次()。既安全又快捷。这个always策略在实践中非常缓慢,但它支持组提交,因此如果存在多个并行写入,Redis将尝试执行single fsync操作。

如果我的AOF被截断了我该怎么办?

有可能是服务器在写入AOF文件时崩溃,或者存储AOF文件的卷在写入时已满。当这种情况发生时, AOF仍包含一致的数据,表示数据集(dataset)的给定时间点版本(在默认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

    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部分都可能被丢弃,如果文件的初始部分碰巧发生损坏,则会导致大量数据丢失。

工作原理

日志重写使用与快照相同的 copy-on-write trick 。它是这样工作的:

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

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

  • 父进程将所有新更改累积到内存缓冲区中(但同时它将新更改写入旧的仅附加文件中, 因此,如果重写失败,我们是安全的)。

  • 当子进程重写完文件后,父进程将得到一个信号,并将内存缓冲区追加到由子进程生成的文件末尾。

  • OK!现在Redis会自动地将旧文件重命名为新文件,并开始向新文件中添加新数据。

如果我当前使用的是dump.rdb快照,如何切换到AOF?

在Redis 2.0和Redis 2.2中有一个不同的过程来实现这一点,因为你可以猜到在Redis 2.2中它更简单,而且根本不需要重新启动。

Redis>=2.2

  • 备份最新的dump.rdb文件。
  • 把这个备份转移到一个安全的地方。
  • 使用以下两个命令:
redis-cli config set appendonly yes
redis-cli config set save ""
  • 请确保您的数据库包含与其包含的相同数量的键。
  • 确保写入操作正确附加到仅附加文件(appendonly.aof)。

第一个CONFIG命令启用仅附加文件。为了这样做Redis会阻止要生成initial dump,则将打开文件进行写入,并开始附加所有下一个写入查询。

第二个CONFIG命令用于关闭快照持久化。这是可选的,如果您希望可以同时启用这两个持久化方法。

重要提示:记住编辑redis.conf以打开AOF,否则 重新启动服务器时,配置更改将丢失,服务器将使用旧配置重新启动。

Redis 2.0版

  • 备份最新的dump.rdb文件。
  • 把这个备份转移到一个安全的地方。
  • 停止对数据库的所有写入操作!
  • 执行redis-cli BGREWRITEAOF. 这将创建仅附加文件(appendonly.aof)。
  • 当Redis完成生成AOF转储时停止服务器。
  • Edit redis.conf 确保启用仅附加文件持久化。
  • 重新启动服务器。
  • 请确保您的数据库包含与其包含的相同数量的键。
  • 确保写入操作正确附加到仅附加文件。

AOF与RDB持久化的交互作用

Redis>=2.4确保避免在RDB快照操作已在进行时触发AOF重写,或允许BGSAVE当AOF重写正在进行时。这可以防止两个Redis后台进程同时执行重磁盘I/O。

当进行快照时,用户使用BGREWRITEAOF显式请求日志重写操作时,服务器将以OK状态码答复,告知用户已计划该操作,并且快照完成后将开始重写。

如果同时启用了AOF和RDB持久性,并且Redis重新启动,则AOF文件将用于重建原始数据集,因为它可以保证是最完整的。

备份Redis数据

没有备份意味着数据丢失存在巨大风险。

Redis非常便于数据备份,因为您可以在数据库运行时复制RDB文件:RDB一旦生成就永远不会被修改,而RDB在生成时会使用一个临时名称,并且当新快照完成后仅使用rename原子地重命名为其最终目标。

这意味着在服务器运行时复制RDB文件是完全安全的。我们建议:

  • 在服务器中创建一个cron job,在一个目录中创建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客户端密钥,然后将其添加到小型VPS的authorized_keys文件中。您已准备好以自动方式传输备份。在两个不同的提供商中获得至少两个VPS,以获得最佳结果。

重要的是要理解,如果未正确实施此系统,该系统很容易发生故障。至少要绝对确保在传输完成之后,您能够验证文件大小(该大小应与您复制的文件之一匹配),如果使用的是VPS,也可以验证SHA1摘要。如果由于某些原因无法传输新备份,则还需要某种独立的警报系统。

参考文档:https://redis.io/topics/persistence

原文地址:https://www.cnblogs.com/crelle/p/13732896.html