0x000 概述
这篇文章概括了关于Redis
持久化技术,推荐所有的Redis
用户都应该阅读。关于Redis
持久化和健壮性保证详细信息可以查看这篇文章-解密Redis
持久化。
0x001 Redis
持久化
Redis
提供了一系列不同的持久化选项:
-
RDB
持久化可以指定定时器定时捕捉数据集快照。 -
AOF
持久化记录每一次服务端收到的写操作,并在服务端重新驱动的时候再次执行,重构原始数据集。命令的记录使用的是Redis
本身的命令格式,并且是拼接式的。当它变得太大的时候,Redis
可以在后台重写记录。 - 如果你希望你的数据只是在服务端运行的时候存在,你可以完全关闭持久化。
- 在同一个实例上将
AOF
和RDB
结合起来使用也是可以的。要注意,在这种情况下,Redis
重启的时候,将会使用AOF
文件来重构原始数据,因为它保证数据的完整性。
明白如何权衡取舍AOF
和RDB
持久化就最重要的。先从RDB
开始:RDB
优点:
-
RDB
是一个结构紧凑的单文件,他代表你的数据集在某个时间点的快照。RDB
文件用来做备份是非常完美的,比如你可以24个小时之内每个小时打包一个RDB
文件,并且吧每天RDB
快照保存30天。这允许你很简单的就保存数据不同的数据版本,可以很好的用于灾备。 -
RDB
对于故障恢复非常好,因为单个结构紧凑的文件可以转移到很远的数据中心,或者在Amazon S3
(可能需要加密) -
RDB
使得Redis
的性能最大化,因为Redis
主线程唯一要做的事就是创建子进程,剩下的事都交给子线程去完成。主线程将不会执行磁盘I/O
操作。 - 相对与
AOF
来说,当数据集很大的时候,RDB
可以很快的重启。
RDB
缺点:
- 如果你希望在
Redis
突然停止工作的时候丢失的数据最少(比如停电),那么RDB
并不好。你可以配置不同的时间点来创建RDB
(比如至少5分钟并且有100条写入命令,但你可以有多个保存点)。然而大部分情况下,我们总是每5分钟或者更长一点的时间创建一个RDB
镜像,所以,如果Redis
因为某些原因,并没有正常的关机,你必须做好丢失最新几分钟的数据的准备。 -
RDB
为了使用子进程去完成持久化操作,需要经常调用fork()
函数,fork()
在数据集比较大的时候是非常耗时的,如果数据集非常多并且CPU
性能并不是很好,可能会导致Redis
暂停服务几毫秒,甚至1秒。AOF
也需要调用fork()
,但是你可以不需要权衡的调整多久重写日志。
AOF advantagesAOF
的优点:
-
AOF
的耐久性更好:你可以有不同的文件同步策略:完全不使用文件同步,每秒都使用文件同步,在每次查询的时候文件同步。默认策略是每秒都使用文件同步,虽然如此,写性能依旧出色,你最多只会丢失1秒的写入数据。 -
APF
的日志是追加型的日志,所以在突然停电的时候不会多,也不会少。即使因为某些原因(比如磁盘满了)日志的结尾只写入了半个命令,redis-check-aof
工具也可以简单的修复。 - 如果日志文件太大,
Redis
可以自动的在后台重写AOF
。重写操作也是完全安全的,Redis
可以继续追加数据到旧的文件,新的文件将会以最小操作需要去创建当前的数据集,当新文件创建并准备好,Redis
就会将两者调换,并开始写入到新的文件。 -
AOF
的日志包含了所有的操作,格式良好并且容易理解。你甚至可以很简单的导出AOF
文件。比如就算你使用FLUSHALL
命令,只要你在这期间没有重写日志文件,你也可以停止你的服务端,保存你的数据,移除最新的命令,然后重启Redis
。
*AOF disadvantagesAOF
缺点
- 对于同一个数据集,
AOF
文件总是比RDB
的文件大。 -
AOF
比RDB
慢,因为AOF
精确的文件同步策略。在通常情况下,每秒的文件同步策略的性能也是非常好的,如果禁止文件同步策略,性能将和RDB
一致,就算在高负载之下。RDB
在高写入负载下依旧可以提供更好的最高延迟保障, - 在过去的时候,在一些特殊的命令上,我们遇到过非常罕见的bug(比如像
BRPOPLPUSH
这种堵塞命令),导致AOF
在重新加载的时候没有产生和原数据集相同的数据集。这种bug是非常罕见的,我们在测试用例中自动创建了随机的复杂的数据集,然后重新加载他们并且检查发现所有的东西都没有问题,但是这种问题在RDB
持久化中几乎不可能存在。让这个观点更明确一点:AOF
增加更新一个已经存在的状态,就像MysSQL
或者MongoDB
那样,然而RDB
抓取所有的数据并创建快照,这在概念上更加的健壮。然而,一来需要注意的是每一次AOF
重写都是从真实数据集的开始抓取并重新创建,出现的bug和追加AOF
文件相比更加的麻烦(或者一次重写读取的是旧的AOF
文件而不是从内存中读取)。二来在真实世界中吗我们没有接到过一个关于AOF
命令重复的报告。
0x0002所以我们应该使用哪个?
通常来说,如果你想要达到PostgreSQL
那种数据安全性,我们应该结合两种持久化方式来使用。
如果你比较关心你的数据,但是依旧可以接受几分钟的数据丢失,那你可以只是简单的使用RDB
。
非常多的用户都只是单独的使用AOF
,我们并不鼓励这种做法,因为实时拥有一个RDB
快照作为备份是一个非常好的做法,为了更快的重启或者放置AOF
引擎的bug。
注意:因为这些原因,在未来,我们可能会终止AOF
和RDB
持久化方式的合并(长的团队计划)。
接下来的章节将会更加详细的解释两种持久化模式。
0x003 快照
默认情况下,Redis
将数据集的快照在磁盘上保存成一个名为dump.rdb
的文件。你可配置Redis
在几秒内数据集有多少变化的时候保存快照,或者你也可以直接的使用SAVE
和BGSAVE
命令。
比如,下面这个配置将会让Redis
在60秒内产生1000个key
的改变的时候自动创建数据集快照。
save 60 1000
这种策略就是快照。
0x004 他是怎么工作的
每当Redis
需要导出数据集到磁盘的时候,将会发生下面的事:
-
Redis
调用fork()
,就有了一个子进程和主进程 - 子进程将数据集写入临时的
RDB
文件 - 当子进程写入新的
RDB
文件完成的时候,将会覆盖旧的文件。
这个方法允许可以用复制并写入来形容这个方法。Redis
从copy-on-write
语义中获得好处。
0x005 只允许追加的文件
快照的持久性并不是很号,如果你的电脑将Redis
停了,或者你的生产线停了,或者你意外使用kill -9
停止了你的实例,最新写入Redis
的数据将会丢失。这对于一些应用来说是一个大问题,他们需要很高的持久性,在这种情况下Redis
并没有很好的选项。
可以使用全量持久性策略来替代追加文件策略。这在1.1
版本就被支持了。
你可以在你的配置文件中开启:
appendonly yes
从现在开始,每次Redis
接收到改变数据集的命令(比如SET
),他将会追加数据到AOF
。当重启的时候,他将会使用AOF
文件重构状态。
0x006 日志重写
就像你猜的,越多的写操作被执行,AOF
就会变得越大,比如,如果你将一个计数自增100次,最终在数据集中,将会有一个单独的key
,但是在AOF
中将存在100条记录,其中99条对于重构当前状态是没有必要的的。Redis
支持一个很有趣的特性:可以不打断当前服务的情况下在后台重构AOF
。不论你何时调用BGREWRITEAOF
,Redis
都会将重构当前数据集必要的最短的命令序列写入文件。如果你在Redis 2.2
中使用AOF
,,你需要时不时执行BGREWRITEAOF
。Redis 2.4
以后可以自动执行日志重写(可以查看2.4的案例配置文件获取更多详细情况)。
0x007 只支持追加文件的健壮性如何?
你可以配置文件同步到磁盘的频率。有三个参数:
- 当有新的命令被追加到
AOF
的时候就文件同步一次。非常慢,非常安全。 - 每秒一次。非常快(在2.4和快照一样快),你在故障的时候只会丢失一秒的数据
- 从来不同步,这是吧数据交给操作系统,更快但是最不安全的方法。
推荐(默认)的策略是每秒文件同步一次。不但快而且安全。在实践中这种策略总是非常慢的(尽管在2.0中改善了)-没有什么办法可以让他更快了
0x008 AOF
出错的时候该怎么错?
如果服务端在写入AOF
文件的时候出错了(这从来没有导致不一致),因为某种原因出错让Redis
无法加载它。当发生这种事的时候可以使用下列步骤修复:
- 复制
AOF
文件 - 使用
redis-check-aof
工具修复:
$ redis-check-aof --fix
- 还可以使用
diff -u
来对比两个文件的差异 - 使用修复后的文件重启服务。
0x009 这是怎么工作的
- 日志重写使用和快照相同的复制并写入的技巧,它是这么工作的:
-
Redis
创建进程,所以现在有一个子进程和一份主进程。 - 子进程开始写入新的
AOF
临时文件 - 主进程在内存中缓存新的改变(同时,将新的变化写入旧的文件,所以,如果重写失败了,我们的数据还是安全的)
- 子进程重写文件完成以后,主进程得到信号,将内存中的缓存追加到子进程生成的文件中。
- 接着
Redis
重命名旧的文件为新名字,同时开始追加新数据到新文件。
0x010 如果在使用dump.rdb
快照,如何切换到AOF。
这个操作在Redis2.0
和Redis2.2
中是不一样的,就像你猜的,在Redis 2.2
中非常简单,并且完全不需要重启。
Redis >= 2.2
- 备份最新的数据到
dump.rdb
- 将备份文件放到安全的地方
-
执行下面两个命令
$ redis-cli config set appendonly yes $ redis-cli config set save ""
- 确保你的数据库包含相同数量的
key
- 确保写入操作被正确追加到只允许追加的文件
第一个CONFIG
操作启用Append Only File
,为了让Redis
阻塞并生生初始化转存,他们将会打开文件并写入,开始追加接下来所有的写入操作。
第二个CONFI
命令用来关闭快照持久化。这是可选的,你可以让两个持久化方法都启用
重要:记住修改你的redis.conf
文件去启用AOF
,否则当你重启服务端的时候配置的改变将会丢失,并且你的服务端将会以旧的配置文件启动。
Redis 2.0
- 备份最新的数据到
dump.rdb
- 将备份文件放到安全的地方
- 停止所有的写入操作
- 调用
redis-cli bgrewriteaof
。将会创建一个只支持追加的文件 -
Redis
生成完成AOF
文件的时候停止服务端 - 编辑
redis.conf
启用只支持追加文件持久化 - 重启服务端
- 确保你的数据库包含相同数量的
key
- 确保写入操作被正确追加到只允许追加的文件
0x011 AOF
和RDB
持久化的相互影响
Redis 2.4
以后RDB
快照操作执行的时候,不会让AOF
重写执行,当AOF
重写在执行的时候,也不会让BGSAVE
执行,这阻止了两个Redis
进程同时做过于繁重的磁盘I/O
操作
当快照正在执行的时候,如果用户显式子的调用BGREWRITEAOF
,服务端将会回复OK
状态码,告诉用户操作已经在日程中,重写将会在快照完成之后执行。
在AOF
和RDB
都开启的场景下,Redis
重启后将会使用AOF
文件重构原始的数据集,因为它更能保证数据完整。
0x012 备份Redis
数据
在开始这个章节之前,有些东西必须知道:保证备份你的数据。磁盘损坏,云中的实例消失了或者其他情况:没有备份意味着你将冒着数据放到/dev/null
的巨大风险。
Redis
对数据备份是非常友好的,因为你可以在数据库运行的时候复制RDB
文件:RDB
文件一旦创建就不再修改,而且生成的时候使用的是临时的名字,它将在最终目标生成完成的的时候自动重命名。
这意味着当服务端运行的时候复制RDB
文件是完全安全的。这是我们的建议:
- 在你的服务器创建一个
cron
任务,每小时创建一个RDB
快照文件放在一个文件夹,每天创建一个RDB
快照文件放在另一个文件夹。 - 每次执行
cron
脚本的时候,确保太旧的文件被删除:按小时备份的数据,你可以保存最新的48小时的,按天备份的,你可以保存一道两个月的。确保快照的命名有日期和时间信息。 - 至少每天一次的确保将
RDB
快照文件放到你的数据中西或者至少不放在你运行Redis
实例的物理服务器上。
0x013 故障恢复
故障恢复在Redis
的场景中也是非常基础的操作,就像备份一样,因为他可以吧备份放置到外部的数据中心。在这种情况下,就算在Redis
运行并产生快照的主要的数据中心发生一个大突变,数据也是安全的。
因为很多Redis
使用者都在初创场景,没有太多的资金,所以我们将会回顾大部分有趣的却不需要耗费大多的故障恢复技术。
-
Amazon S3
和其他一些类似的服务商是挂在你的故障恢复系统的号方式。用加密的形式将你每小时或者每天生成的RDB
快照传输到S3
。确保将你的密码到不同的安全的地方(比如给你组织的其他成员一个备份)。使用多个存储服务商是提高数据安全性是非常值得推荐的。 - 使用
SCP
(SSH
的一部分),远程传输你的快照。这是一个非常简单却安全的路由:在一个距离你很远的地方买一个VPS
并安装SSH
,使用key
而不是用密码,添加authorized_keys
文件到VPS
。你就可以自动传输你的备份了,在两个不同服务商购买VPS
会更好。
这个系统如果没有以正确的方式编码是很容易失败的。如果你使用VPS
,至少绝对保证可以验证传输之后的文件大小(它和你复制的文件应该一样大),或者可以验证SHA1
。
你当然也需要一些报警系统,为了防止备份传输工作因为某些原因而没有正确的工作
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。