redis的持久化

来源:转载


本文提供了关于redis持久化的技术描述,适用所有的redis用户阅读。如果想要更加全面地了解redis持久化及它提供的持久保障,你可能还需要阅读《redis持久化揭秘》

redis持久化

redis提供了不同幅度的持久化选项:

  • RDB持久化对你的数据集基于特定的时间间隔执行时间点快照。
  • AOF持久化在每次服务器收到写操作时记入日志,当服务器重启时,这些写操作会再次执行,重构出原始的数据集。
  • 命令以只能追加的方式记入日志,记入的格式与redis协议本身相同。当日志太大时,redis会重写日志。
  • 如果你想让你的数据只在服务器运行的时候存在,可以按照你的要求完全关闭持久化功能。
  • 可以在同一个实例中结合使用AOF和RDB。注意,在这种情况下,redis重启时使用AOF文件重构原始数据集,因为这样得到的数据集更完整。

最重要的事情就是理解RDB持久化和AOF持久化之间的差别与权衡。先从RDB开始:

RDB的优点

  • RDB是压缩的单个文件,表示你的某一时刻的redis数据。RDB文件非常适合备份。假如你把最近24小时中每个小时的RDB文件存档,并把最近30天每天存储一个RDB快照。这样遇到数据灾难时你就能容易地恢复各种版本的数据集了。
  • RDB适用于灾难恢复,作为一个单个的紧凑的文件,能够传输到远端的数据中心,或传到亚马逊S3(最好加密)。
  • RDB把redis的性能最大化。因为对于redis父进程,如果要执行持久化,唯一要做的就是创建一个子进程,而子进程会做所有的事情。父进程不需要执行磁盘I/O或者其它类似操作。
  • 对于数据集较大的情况,相较于AOF,RDB使得重启更快。

RDB的缺点

  • 在Redis停止工作的情况(例如断电)下,如果你想要使数据丢失的可能性最小,RDB并不合适。你可以设置不同的保存点,在保存点上会生成RDB(例如至少5分钟且100次对数据集的写操作以后。你也可以设置多个保存点)。然而,你通常会设置成每5分钟或更长时间生成一个RDB快照。在这种情况下,如果redis因为什么原因没有经过正常关机而停止工作,你会丢失最后几分钟的数据。
  • RDB需要经过fork()通过子进程写磁盘。如果数据集很大,fork()是非常耗时的,可能导致redis在几毫秒甚至1秒的时间里停止向客户端提供服务且CPU性能也不好。AOF也需要fork(),但你可以调节重新日志的频率而不需要任何牺牲。

AOF的优点

  • AOF更加可靠:你可以有不同的文件同步策略:没有文件同步,每秒同步,每次请求时同步。默认为每秒同步,写性能也不错(文件同步使用一个后台线程,当没有进行文件同步时,主线程会执行写操作),你只会丢失1秒内的写数据。
  • AOF的日志只能追加,因此也没有搜索操作,断电时也不会有丢失问题。即使由于某种原因(磁盘满或其它原因)导致最后一条命令只记录了一半,redis-check-aof工具也能很容易的修复它。
  • 当AOF文件太大时,redis能够在后台自动重写AOF。重写是完全安全的。因为当redis继续向旧文件追加内容时,产生的新文件包含能够产生当前数据集的所需要的最小命令集。一但新文件准备好了,redis就会切换到第二个文件,向这个新文件追加内容。
  • AOF使用一种方便理解和分析的格式,一条一条地记录所有操作的日志。你可以很容易地导入一个AOF文件。即使你由于错误地使用FLUSHALL命令冲掉了所有命令,如果在此期间没有没有重写日志,你仍然可以恢复数据,只需要停止服务器、移除最后一条命令,然后重启服务器就可以了。

AOF的缺点

  • 相较于相同数据集同等情况下的RDB文件来说,AOF文件通过很大。
  • 由于精确同步策略,AOF比RDB慢。通常情况下,每秒文件同步的性能仍然很好,而无文件同步的AOF和RDB的速度一样快,即使是在高负载的情况下。然而,对于大量的潜在问题,RDB还能提供更多的保障,即使是大规模的写。
  • 以前,我们对某些特殊的命令(例如一个涉及到阻塞的命令,BRPOPLPUSH)测出的bug很少,导致生成的AOF文件不能在重新加载时生成完全一样的数据集。这个bug不常见。我们在测试时自动创建随意的复杂的数据集并重新加载它们,检查是否一切正常。但这种问题在RDB持久中几乎不存在。更清楚地讲:Redis的AOF的工作原理是更新一个已经存在的状态,类似MySQL和MongoDB的作法,而RDB一次又一次地生成快照,这从理论上更健壮。然而,(1)注意,每次redis重写AOF时,它是从数据集中实际的数据开始,相对于一味向AOF追加(或重写时读取旧的AOF而不是内存中的数据)来说,这使它更强壮【1】。(2)我们至今没有发现一个来自用户的在真实使用中检测出AOF丢失数据的报告。

RDB还是AOF?

通常建议同时使用两种持久化方法,如果你希望数据安全性能够与PostgreSOL所提供的安全性相比。
如果你关心数据,但仍能够允许在灾难时能够有几分钟的数据丢失,你可以只使用RDB。
还有许多用户只使用AOF,但我们不推荐。因为实时的RDB快照对于数据库备份、快速重启都是很好的。
注意:由于这些原因,我们倾向于在将来把AOF和RDB统一成一个持久化模型(长期计划)。
下面的章节会对这两个持久化模型进行更详细的描述。

快照

默认情况下,redis把数据集的快照以二进制文件的保存到硬盘上,名为dump.rdb。你可以这样配置redis,当数据集至少发生M次变化时,每N秒保存数据集一次,你也可以手动调用SAVEBGSAVE命令。
举个例子,这样配置,当数据集至少1000个键发生改变时,redis就会每60秒一次把数据集的保存(dump)到硬盘上。

save 60 1000

这个策略被称为快照。

工作原理

当Redis要把数据集保存(dump)到硬盘时,会发生这些:

  • 创建子进程。现在有一个子进程和一个父进程了。
  • 子进程开始把数据集写到一个临时的RDB文件中。
  • 当子进程完成写RDB文件时,这个RDB文件替换原来的RDB文件。

这个该当使得Redis能够受益于写时复制。

仅追加文件

快照并不可靠。如果你的电脑上的redis停止运行,或电脑断电,或实例意外收到kill -9,最后写到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将数据同步到硬盘的次数。有三个选项:

  • 每次有一个新的命令增加到AOF时进行文件同步。非常非常慢,非常安全。
  • 每秒文件同步。足够快(在2.4版本中,大概和快照一样快),如果发生灾难,会丢失1秒的数据。
  • 从不文件同步,由操作系统管控你的数据。更快,但不太安全。

建议(默认)策略是每秒同步。既快又相对安全。在实际操作中,第一种策略非常慢(尽管在2.0版本中做了改进),也不可能再快了。

AOF损坏时怎么做?

有可能在正在写AOF文件时服务器崩溃(这仍然不会导致不一致),这会损坏AOF文件,使它不能再被redis加载。你可能通过以下过程修复这个问题:

  • 备份你的AOF文件
  • 使用redis-check-aof工具修复原始文件,这个工具跟随redis一起发布:
$ redis-check-aof --fix
  • 选择性地使用diff -u检查这两个文件有什么不同。
  • 使用修复的文件重启服务器。

工作原理

日志重写使用了与快照中使用的写时复制技术相同,这是它的工作原理。

  • redis创建一个子进程,现在有一个子进程和一个父进程了。
  • 子进程把新的AOF写到一个临时文件。
  • 父进程把所有新的改变积累到一个内存的缓冲区中(同时也会把新的改变写到旧的追加文件中,这样即使重写失败了也是安全的)。
  • 子进程完成重写后,父进程得到一个信号,把内存缓冲区的的命令追加到由子进程创建的新文件的结尾。
  • 好处!现在redis自动把新文件重命名为旧的文件名,开始把数据追加到新文件中。

如果我现在使用的是dump.rdb快照,我怎么切换到AOF?
在2.0版本和2.2版本中,这个过程是不一样的。如你所想,在2.2版本中会简单点,不再需要重启。

redis 2.2以上版本

  • 备份最新的dump.rdb文件
  • 把备份文件转移到一个安全的地方
  • 执行下面这两个命令:
redis-cli config set appendonly yesredis-cli config set save “”
  • 确认你的数据库包含的键的数目相同
  • 确认写操作会正确地添加到追加文件后面。

第一个CONFIG命令打开追加文件的使能。为了达到这个目的,Redis**会阻塞**并生成初始的dump,然后打开文件用于写,然后开始追加所有接下来的写请求。
第二个CONFIG用于关闭快照持久化。这是可选的,你也可以同时打开两个持久化方法。
重要:记得编辑你的redis.conf打开AOF,否则当你重启服务器时修改的配置会丢失,服务器又会启用旧的配置。

redis 2.0版本

  • 备份最新的dump.rdb文件
  • 把备份文件转移到一个安全的地方
  • 停止所有对数据库的写操作!
  • 在客户湍执行bgrewriteaof。这个创建一个仅追加属性的文件。
  • 当生成完AOF dump时停止服务器。
  • 编辑redis.conf,打开追加文件持久化的使能。
  • 重启服务器。
  • 确认你的数据库包含的键的数目相同
  • 确认写操作会正确地添加到追加文件后面。

AOF持久化与RDB持久化之间的交互

redis 2.4以上版本可以保证不会在执行RDB快照的时候触发AOF重写,也不会允许在AOF重写期间BGSAVE。这避免了两个redis后台进程同时做耗时的硬盘操作。当正在执行快照时,如果用户使用BGREWIRETEAOF命令显式地请求日志重写操作,服务器会返回OK的状态码,告诉用户这个操作被列入计划中,一早快照完成立即开始重写。
在同时开启AOF和RDB的情况下,Redis重启时AOF文件会被用于重建原始数据集,因为这样能保证数据最完整。

备份Redis数据

在开始这一章节之前,请阅读这句话:务必备份数据库。硬盘损坏,云上的实例消失,等等。没有备份意味着数据清空的巨大风险。
redis对于数据备份非常方便,你可以在数据库运行时拷贝RDB文件:RDB文件一但生成不会改变。由于生成时使用一个临时的名字,新的快照完成后它自动地使用rename(2)重命名成目标名字。
这意味着在服务器运行时拷贝RDB文件是完全安全的。这是我们建议:

  • 在你的服务器创建一个长期作业,它负责每小时创建一次快照,并存放到同一个目录下,把每天的快照放在不同的目录下。
  • 每次运行作业脚本时,确保调用find命令以确认太旧的快照已被删除:例如你可以对最近的48小时做每小时快照,对最近的一两个月做每天快照。确保根据快照的数据和时间对快照命令。
  • 至少每天一次把RDB快照转移到数据中心以外或redis实例运行的机器以外。

灾难恢复

redis的灾难恢复实际上就是在备份功能的基础上,增加在不同外部数据中心之间传输备份的能力。通过这种方式,即使由于某个灾难事件影响到了redis所运行的数据中心及它所产生的快照,但数据仍然是安全的。
由于许多redis的用户都处在创业阶段,并没有很多钱,因此我们回顾一下非常有趣但不需要太多花费的灾难恢复技术。

  • 亚马逊S3和其它相似的服务装备你的灾难恢复系统的好方式。只需要以加密的方式把每天或每小时的RDB快照上传到S3。你可以使用gpg
    -c(对称加密模式)加密你的数据。确保把你的密码夏至许多不同的安全的地方(例如把一个复制版本交给你的组织中最重要的成员)。建议使用多个存储服务来增加数据的安全性。
  • 使用SCP(SSH的组成部分)把快照传到远端服务器。这是一种非常简单且安全的方法:在离你非常远的地方获取一个虚拟服务器,在那里安装ssh,生成一个不需要密码的ssh客户端密钥,把它加到你的虚拟服务器上的“认证的密钥”文件。你可以自动地传送备份文件
    了。最好至少在两个不同的提供者那里获取两个虚拟服务器。

如果没有正确地编码,系统会很容易就挂掉,认识到这点很重要。至少一定要确认传输完成后查看文件大小(应该与原文件大小相同)。如果使用了VPS的话,最好还要确认一下SHA1的摘要。
如果由于某种原因,传输备份文件不可以行的话,你需要一个独立的报警系统,

原文:
【1】 It should be noted that every time the AOF is rewritten by Redis it is recreated from scratch starting from the actual data contained in the data set, making resistance to bugs stronger compared to an always appending AOF file (or one rewritten reading the old AOF instead of reading the data in memory).



分享给朋友:
您可能感兴趣的文章:
随机阅读: