Redis提供了两种不同级别的持久化方式。一种是RDB(Redis DataBase),另一种是AOF(Append Only File)。
一、RDB(Redis DataBase)
1、什么是RDB
RDB持久化方式是指在指定的时间间隔内将内存中的数据集快照写入磁盘。当重启Redis时将快照文件直接读到内存里。
2、如何触发RDB快照保存策略
有三种方式触发RDB持久化策略
- 通过配置文件中配置save <seconds> <changes> (后面具体介绍),自动触发。
- 通过调用SAVE或BGSAVE命令,手动触发。SAVE时只管保存,其它不管,全部阻塞,不建议。BGSAVE时Redis会在后台异步进行快照操作,快照保存的同时还可以响应客户端请求。
- 通过调用FLUSHALL命令。执行FLUSHALL命令也会 产生RDB文件,但里面是空的,无意义。
可以通过LASTSAVE命令查看最后一次成功执行快照的时间。
3、RDB的持久化流程
当Redis需要保存RDB文件时,服务器执行以下操作:
- 若有其他子进程正在执行,则直接返回;否则Redis调用fork方法单独创建一个子进程来进行持久化,此时Redis同时拥有父进程和子进程;
- 子进程将数据写入到一个临时的RDB文件中;
- 当子进程完成写入后,在用这个临时文件替换上次持久化好的文件。
在Linux系统中,fork()会复制一个与当前进程一样的进程。一般情况下父进程和子进程会共用同一段物理内存,所以子进程的所有数据(包括变量、环境变量。程序计数器等)都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。当进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程。
4、RDB的相关配置
- save <seconds> <changes>
Redis在指定的秒数内有指定个写操作时触发RDB快照存储。
默认RDB有三种保存策略:
i)save 3600 1 (在3600秒即一个小时内至少有1个键发生改变)
ii)save 300 100(在300秒即5分钟内至少有100个键发生改变)
iii)save 60 10000(在60秒即1分钟内至少有10000个键发生改变)
不设置save或使用save ""可以禁用RDB。 - dbfilename
配置RDB文件名。
默认情况下,Redis将数据库快照保存在名字为dump.rdb的二进制文件中 - dir
RDB文件和AOF文件的保存路径。默认是./(Redis启动时命令行所在的目录下)。 - stop-writes-on-bgsave-error
当Redis无法写入磁盘的话,直接关掉Redis的写操作。默认启用。
默认情况下,如果RDB快照被启用,并且最近一次保存数据时失败,Redis将停止接受写
操作。如果后台保存进程再次开始工作,Redis将自动允许写操作。推荐启用。 - rdbcompression
存储数据集快照到磁盘中生成RDB快照时是否启用LZF算法压缩字符串对象。默认启用。 若不想子进程在生成RDB文件时消耗CPU来进行压缩的话,可以禁用此功能,但是生成的 RDB文件会更大一些。推荐启用。 - rdbchecksum
是否启用CRC64校验和。默认启用。若启用,在存储快照后,redis将使用CRC64算法来 进行数据校验,并将校验和置于RDB文件的末尾,这使得RDB文件的格式更不容易被破 坏。当时这样做在保存或加载RDB文件的时候会增加大约10%的性能消耗。如果想最大化 Redis性能,可以禁用此功能。当禁用时,RDB文件末尾的校验和为0,当Redis重启并加 载该RDB时将跳过校验。推荐启用。 - sanitize-dump-payload
加载RDB文件或恢复数据时是否启用ziplist和listpack检查。有助于减少以后在处理命令时 发生断言和错误的机会。有下面三种模式:
i)no (不检查)
ii)yes(总是检查)
iii)clients(只对用户连接执行检查。排除接收到主服务器的RDB文件和恢复命令以 及带有"skip-sanitize-payload ACL"标识的客户端连接)
默认值应为"clients",但由于它当前影响通过主服务器重新分片集群,因此默认情况下暂 时设置为"no"。 - rdb-del-sync-files
主从复制时,是否删除用于同步的从机上的RDB文件。默认是no。只有当从机未开启RDB和AOF才生效。
5、RDB文件的备份与数据恢复
磁盘故障,节点失效,诸如此类的问题都可能让数据消失不见,不进行备份是非常危险的。因此需要确保数据有完整的备份。Redis 对于数据备份是非常友好的,可以在服务器运行的时候对RDB 文件进行复制。因为RDB 文件一旦被创建,就不会进行任何修改。当服务器要创建一个新的 RDB 文件时, 它先将快照数据保存在一个临时文件里,当临时文件写入完毕时, 程序才使用 rename(2) 原子地用临时文件替换原来的 RDB 文件。所以无论何时, 复制 RDB 文件都是绝对安全的。
若要备份最近一次RDB文件,可先通过config get dir查询RDB文件的目录。然后将RDB文件拷贝到别的地方,最好将 RDB 备份到数据中心之外,或者至少是备份到运行 Redis 服务器的物理机器之外。
若想Redis中的数据恢复到指定的快照版本,可以先关闭Redis,然后把之前备份的指定版本的RDB文件拷贝到工作目录中,重启Redis,备份数据就会被直接加载进内存了。
6、如何停止RDB
若在Redis运行时停止RDB持久化模式,可以执行以下命令:
redis-cli config set save ""
当Redis重启时,上面命令将会失效。可以修改配置文件,以后每次重启后都不会进行RDB存储。
7、RDB的优缺点
优点
- RDB文件小而紧凑,它保存的是某个时间点的数据,适合大规模的数据恢复;
- RDB文件可以很方便的传送到远端数据中心,适合灾难恢复;
- RDB可以最大化Redis性能,因为父线程唯一要做的就是fork一个子进程,数据存储的工作全部由子进程来完成,父进程不需要再做其他的IO操作。因此更适用于对数据完成性和一致性要求不高的场景;
- 节省磁盘空间
- 与AOF相比,在恢复大规模的数据时,RDB速度更快,提供了更有保证的最大延迟时间。
缺点
- 若Redis服务器宕机,会丢失最后一次持久化后的所有数据;
- fork的时候,内存中的数据被克隆了一份,有大致2倍的膨胀性;
- 消耗性能。当数据比较大时,可能会导致Redis毫秒级内不能客户端的请求。因为当数据量比较大时,fork的过程非常耗时,虽然Redis在fork是使用了写时复制技术,但还是会比较消耗性能。AOF也需要fork,但是可以通过调节重写AOF文件的频率来提高数据的持久度。
二、AOF (Append Only File)
如果使用RDB持久化方式,当Redis因为某些原因宕机,那么将丢失最近一次快照保存后写入的数据。为了更好的保证数据完整性和一致性,从1.1版本开始,Redis增加了AOF持久化。
1、什么是AOF
所谓AOF就是以日志的形式记录每个写操作,将Redis执行过的所有写命令记录下来,追加到日志文件中。当Redis重启时,会读取AOF文件,并根据日志文件中的内容将所有写命令从前到后执行一次以完成数据的恢复工作。
AOF能更好的保证数据完整性与一致性。当使用默认的fsync策略时,当Redis服务器宕机或向AOF文件追加一条写入命令时Redis进程出错,那么仅会丢失一秒内的数据。Redis仍可正常运行。
2、如何触发AOF保存策略
AOF默认不开启。若想启用AOF持久化模式需要在配置文件中打开AOF:appendonly yes。AOF文件的保存路径和RDB的相同。
3、AOF的持久化流程
- 客户端请求的写命令会被append追加到AOF输出缓冲区内;
- AOF输出缓冲区根据AOF持久化策略将缓冲区中的内容同步追加到磁盘中的AOF内;
- AOF文件大小超过重写策略或手动重写时,会将AOF文件重写,压缩AOF文件容量;
- Redis服务重启时,会重新加载AOF文件中的写操作达到数据恢复的目的。
4、AOF的相关配置
- appendonly
默认为no,即不开启AOF持久化模式。 - appendfilename
AOF文件的文件名,默认是“appendonly.aof”。 - appendfsync
Redis使用AOF模式记录日志时会调用fsync(),通知操作系统将输出缓冲区中的数据写入 到操盘中,而不是等缓冲区中有更多的数据后再去写入。调用fsync后有些操作系统会立 即将缓冲区中的数据写入到磁盘上,有些操作系统不会立即但会尽快这么做。
AOF保存策略。Redis支持三种AOF保存策略:
i)no (不主动执行fsync进行同步,将同步时机交给操作系统。最快)
ii)everysec(每秒fsync一次。足够快,和使用RDB持久化差不多,在故障时只会丢失 1秒钟的数据)
iii)always (每次写操作fsync一次,即每次Redis的写入都会立刻追加到AOF文件的末 尾。性能较差但数据完整性较好)
默认为everysec模式,该模式兼顾了性能和数据安全。使用no模式将获得更好的性能,但 是会有丢失数据的风险,如果可以接受丢失部分数据,可以考虑使用RDB快照存储。使用 always模式性能会较差,但是将比everysec模式数据安全性更好。 - no-appendfsync-on-rewrite
AOF文件重写时是否将新的写命令写入到磁盘上。默认是no。
当AOF的fsync策略设置为always或everysec时,后台保存或AOF后台重写将会对磁盘进 行大量的I/O操作。在一些Linux配置中,Redis可能会在fsync()调用上阻塞太长时间。因 为即使在不同的线程中执行fsync也会阻塞调用同步的write(2)。
该选项用来防止在BGSAVE或BGREWRITEAOF时候调用fsync()。当设为no时,还是会 把数据往磁盘里刷,但是当子进程重写AOF时,调用fsync()可能会发生阻塞,这意味着 Redis的持久性与"appendfsync no"相同。在最坏的情况下(使用默认的Linux设置),可 能会丢失多达30秒的日志。如果有延迟问题,可以考虑设置为yes,此时若有新的写命令 将不写入AOF文件只写入缓存,用户请求不会阻塞,但是在这段时间如果宕机会丢失这段 时间的缓存数据。从数据的安全性考虑最好设置为no。从性能方面考虑可以设置为yes。 - auto-aof-rewrite-percentage
重写的基准值。默认100。即AOF文件达到100%时开始重写(AOF文件是上次重写后文件 的2倍)。Redis会记录最近一次重写后AOF文件的大小(如果在重启后没有重写,则使用启 动时AOF文件的大小),当AOF文件大小增长到指定的百分比后,将此基础大小与当前大小 进行比较。如果当前大小大于指定的百分比(默认配置是当前AOF文件大小是上次重写后 AOF文件大小的一倍且文件大于64MB时),则会触发重写,Redis会隐式调用 BGREWRITEAOF命令自动重写AOF文件。重写虽然可以节约大量磁盘空间,减少恢复时 间。但是每次重写还是有一定的负担,因此设定Redis要满足一定条件才会进行重写。 - auto-aof-rewrite-min-size
重写的基准值。默认64MB。即使AOF文件增长到auto-aof-rewrite-percentage设置的百分 比,但它仍然非常小时还重写AOF文件会增加系统负担。因此还需要指定AOF文件最小大 小,当AOF文件大小没有达到64MB时不进行重写,用于避免频繁重写AOF文件。 - aof-load-truncated
是否加载损坏的AOF文件。默认是yes。
当设置为yes时,Redis启动时会加载AOF文件,恢复尽可能多的数据并正常启动。Redis 会发送日志通知用户此事。如果设置为no,当启动Redis时将在错误中止并拒绝启动。用 户需要在重启Redis前使用"redis-check-aof"修复AOF文件。 - aof-use-rdb-preamble
当重写AOF文件时,Redis可以在AOF文件中使用RDB的前导来更快地重写和恢复。当设 置为yes时,重写的AOF文件由两个不同的节组成: [RDB file][AOF tail]。当加载时,Redis 识别到AOF文件以“Redis”字符串开始后,会先加载带有前缀的RDB文件,然后继续加载 AOF尾部。
5、AOF文件重写
1、 什么是AOF重写
AOF的运作方式是不断地将写命令追加到日志文件的末尾,随着写入命令的不断增 加,AOF文件会越来越大。为了处理这种情况,新增了重写机制,当AOF文件的大小超 过所设定的阈值时,Redis可以在不打断服务客户端的情况下对AOF文件重写压缩, Redis将生成一个新的AOF文件,这个文件只保留可以恢复数据的最小指令集。整个重写 操作是绝对安全的,因为Redis在重写新AOF文件过程中,会继续将新的写命令追加到原 AOF文件内,即使重写过程中发生宕机,原AOF文件也不会丢失。而一旦新AOF文件创 建完毕,Redis就会从旧AOF文件切换到新AOF文件,并开始对新AOF文件进行追加操 作。Redis4.0版本后的重写就是把RDB快照以二进制的形式附在新的AOF头部,作为已 有的历史数据,替换掉原来的写命令操作。
2、如何触发AOF重写
系统载入时或重写完成时,Redistribution会记录此时AOF文件大小,设为base_size。 如果Redis当前AOF文件大小>=base_size + base_size * 100%(默认) 并且 当前AOF文 件大小>=64MB(默认)的情况下,Redis才会对AOF进行重写。
有两种方式可以出发AOF文件重写:
i)执行BGREWRITEAOF命令,手动触发;
ii)在配置文件中配置重写策略,自动触发。
3、AOF重写的工作原理
AOF重写和创建RDB快照一样, 都利用了写时复制机制。
i)当AOF重写被触发后,判断当前是否有BGSAVE或BGREWRITEAOF在运行,如果 有,则等待改命令结束后再继续执行;
ii)Redis主线程执行fork(),fork一个子进程执行重写操作,主线程不会阻塞,可以继续 响应客户端请求;
iii)子进程遍历Redis内存中的数据并写入到临时文件,若此时客户端有新的写请求时, Redis主进程会将写命令同时写入到aof_buf缓冲区和aof_rewrite_buf重写缓冲区中, 这样保证原AOF文件完整以及新AOF文件生成期间的新的数据修改动作不会丢失。 即使在重写的过程中发生宕机,原AOF文件也还是安全的;
vi)子进程完成重写工作后,会向主进程发送信号,主进程接收到信号后会更新统计信 息,并将aof_rewrite_buf中的所有数据追加到新AOF文件的末尾;
v)Redis原子地用新AOF文件替换旧AOF文件,之后所有写命令都会直接追加到新AOF 文件的末尾。
6、AOF文件的修复
服务器可能在程序正在对AOF文件进行写入时停机,如果停机造成了AOF文件出错,那么 Redis重启时会拒绝载入这个AOF文件,以确保数据的一致性不会被破坏。当发生这种情况 时,可以用以下方法来修复出错的AOF文件:
i)为现有的AOF文件创建一个备份;
ii)使用Redis附带的redis-check-aof程序,对原来的AOF文件进行修复:
$refids-check-aof --fix appendonly.aof
iii)(可选)使用diff -u 对比修复后的AOF文件和原始AOF文件的备份,查看两个文件之 间不同之处;
vi)重启Redis服务器,等待服务器载入修复后的AOF文件,并进行数据恢复。
7、AOF的优缺点
优点
- AOF文件是一个只进行追加的日志文件,所以不需要写入seek,即使由于某些原因,未执行完整的写入命令,也可以使用redis-check-aof工具修复这些问题;
- AOF持久化的数据更完整。每秒fsync,最多丢失1秒的数据,每次写fsync,最多丢失1条数据。备份机制更稳健,丢失数据的概率更低;
- Redis可以在AOF文件过大时自动在后台对AOF文件进行重写,重写后的新AOF文件包含了恢复当前数据集所需的最小命令集合;
- AOF文件有序地保存了对数据库执行的所有写入操作,这些写入操作以Redis协议的格式保存,因此AOF文件的内容非常容易被读懂,对文件进行分析也很轻松。导出AOF文件也非常简单。可以通过操作AOF文件处理误操作。
缺点
- 对于持久化相同的数据集来说,AOF文件要大于RDB文件,比起RDB要占用更多的磁盘空间;
- 根据所选用的fsync策略,AOF的速度可能会比RDB慢。在一般情况下,每秒fsync的性能依然非常高,而关闭fsync即使在高负荷之下也可以让AOF的速度和RDB一样快。在写入载入数据量庞大时,RDB可以提供更有保证的最大延迟时间;
- 恢复备份速度慢于RDB,因为RDB是直接将快照加载到内存,而AOF是重新执行一遍写命令;
- 若选用always的fsync策略,每次读写都同步的话有一定的性能压力;
- 存在个别bug,造成恢复不能。
三、如何选择使用哪种持久化方式
- 若使用Redis只是做内存缓存,可以两种都不用;
- 若十分重视数据安全性,应该同时使用RDB和AOF,这也是官网推荐的;
- 若可以承受数分钟内的数据丢失,可以只使用RDB;
- 官网不推荐只使用AOF持久化方式:因为定时生成RDB快照非常便于进行数据库备份,并且RDB恢复数据集的速度也要比AOF恢复的速度要快,除此之外,使用RDB还可以避免AOF的bug。
四、同时启用RDB和AOF
Redis支持同时启用RDB和AOF,当Redis重启时默认会优先加载AOF文件来恢复数据,因为通常情况下AOF文件保存的数据要比RDB文件保存的数据完整。
五、RDB切换到AOF
在Redis2.2或以上版本,可以在不重启Redis的情况下从RDB持久化方式切换到AOF持久化方式,具体操作如下:
- 为最新的RDB文件创建一个备份;
- 将备份拷贝到一个安全的地方;
- 执行以下两条命令:
redis-cli config set appendonly yes
redis-cli config set save "" - 确保写命令会被正确地追加到AOF文件的末尾。
其中第三步的第一条命令用于开启AOF功能:Redis会阻塞直到初始AOF文件创建完成,之后Redis会继续处理命令请求,并开始将写命令追加到AOF文件末尾。第二条命令用于关闭RDB功能。这一步是可选的,如果愿意的话,也可以同时使用RDB和AOF这两种持久化方式。如果重启Redis,上面的设置将会失效,如果想永久生效的话,要在配置文件中打开AOF功能。
六、RDB和AOF之间的相互作用
在Redis2.4或以上的版本中,BGSAVE和BGREWRITEAOF不可以同时执行,这可以防止两个Redis后台进程同时对磁盘进行大量的I/O操作。
如果BGSAVE正在执行,并且用户显示地调用BGREWRITEAOF命令,那么服务器将向客户端回复一个OK状态,并告知用户,BGREWRITEAOF已经被预定执行,一旦BGSAVE执行完毕,BGREWRITEAOF就会正式开始。