Redis与传统数据库的一个主要区别在于,Redis把所有数据存储在内存中,而传统数据库通常将数据的索引存储在内存,并把实际的数据存储在磁盘中。虽然Redis的数据存储使得用户能以极快的速度读写服务器的数据,但由于内存属于易失存储器,内存所记录的所有数据在系统断电后就会失去,为了解决此问题Redis向用户提供了持久化功能,持久化功能可以把内存中存储的数据已文件形式存储到磁盘中,而服务器也可以根据这些文件在系统重启之后进行数据恢复。为了满足不同的持久化需求,Redis提供了RDB持久化、AOF持久化和RDB-AOF混合持久化等多种持久化方式,如果不需要持久化功能,也可以完全关闭持久化功能,让服务器处于无持久化状态。Redis默认以RDB持久化作为持久化功能。
1.RDB持久化
RDB持久化是Redis默认使用的持久化功能,该功能可以创建出一个经过压缩的二进制文件,该文件包含了服务器在各个数据库中存储的键值对数据等信息。RDB持久化产生的文件均以.rdb后缀结尾,其中RDB表示Redis DataBase(Redis数据库)。
1.1 创建RDB文件的几种方式
Redis提供了多种创建RDB文件的方式:
(1).通过SAVE命令手动创建RDB文件。
(2).通过BGSAVE命令手动创建RDB文件。
(3).通过Redis配置文件设置save选项让服务器在满足指定条件时自动执行BGSAVE命令。
1.1.1 SAVE命令创建RDB文件
执行SAVE命令创建RDB文件会阻塞服务器,它会要求Redis服务器以同步方式创建一个记录了服务器当前所有数据库数据的RDB文件。SAVE是一个无参命令,它在创建RDB文件成功时将返回OK作为结果。
接收到SAVE命令的Redis服务器将遍历数据库包含的所有数据库,并将各个数据库包含的键值对全部记录到RDB文件中。在SAVE命名执行期间,Redis服务器将会阻塞,直到RDB文件创建完毕为止。如果Redis服务器在执行SAVE命令是已经拥有了响应的RDB文件,那么服务器将使用新创建的RDB文件代替已有的RDB文件。SAVE命令复杂度为O(N),其中N为Redis服务器所有数据包含的键值对总数量。执行save命令Redis-server输出日志如下图:
1.1.2 BGSAVE命令创建RDB文件
执行BGSAVE命令会以非阻塞的方式创建RDB文件。因为执行SAVE命令时会阻塞整个服务器,用户在使用SAVE命令创建RDB文件期间Redis将无法为其他客户端提供服务。为了解决此问题,Redis提供SAVE命令的异步版本BGSAVE命令,它与SAVE命令不同之处在于BGSAVE不会直接使用Redis服务器进程创建RDB文件,而是分配一个子进程创建RDB文件。当Redis服务器接收到BGSAVE命令时将执行一下操作:
(1).创建一个子进程。
(2).子进程执行BGSAVE命令,创建新的RDB文件。
(3).RDB文件创建完毕之后子子进程退出并通知Redis服务器进程(父进程)新的RDB文件已创建完毕。
(4).Redis服务器进程使用新创建的RDB文件替换已有RDB文件。
因为BGSAVE命令创建RDB文件的操作是有子进程以异步方式进行的,所以当用户在客户端执行此命令时,服务器将立即向客户端返回OK,然后才会在后台开始具体的RDB文件创建操作。
因为BGSAVE命令是以异步方式执行的,所以Redis服务器在BGSAVE命令执行期间仍然可以继续处理其他客户端发送的命令请求。不过需要注意的是,虽然BGSAVE命令不会像SAVE命令那样一直阻塞Redis服务器,但由于执行BGSAVE命令需要创建子进程,所以父进程占用的内存数量越大,创建子进程这一操作耗费的时间也会越长,因此Redis服务器在执行BGSAVE命令时,仍然可能会由于创建子进程而被短暂地阻塞。BGSAVE命令复杂度为O(N),其中N为Redis服务器所有数据包含的键值对总数量。
1.1.3 通过Redis配置文件配置选项自动创建RDB文件
除了可以使用SAVE命令和BGSAVE命令手动创建RDB文件之外,还可以通过配置Redis配置文件设置save选项,让Redis服务器在满足指定条件自动执行BGSAVE命令:
save <seconds> <changes>
save选项接收seconds和changes两个参数,seconds用于指定触发持久化操作所需要的时长,changes用于指定触发持久化操作所需的修改次数。简单来说,如果Redis在seconds秒内,对其包含的各个数据库总共执行了changes次修改,那么服务器会自动执行一次BGSAVE命令。例如下面的配置:
save 60 10000
上面配置表示服务器在60秒内至少执行了10000次时,服务器就会自动执行一次BGSAVE命令。
Redis允许用户向服务器提供多条save选项,当给选项中的任意一个条件被满足时,服务器就会自动执行一次BGSAVE命令。例如下面的命令:
save 6000 10000
save 600 1000
save 60 10
当以上任意一个条件被满足时,服务器就会自动执行一此BGSAVE命令:
- 在6000秒内(100min),服务器对数据库执行了至少10000此修改。
- 在600秒内(10min)服务器对数据库执行了至少1000次修改。
- 在60秒内服务器对象数据库执行了至少10修改。
注意:为了避免由于同时使用多个触发条件而导致服务器过于频繁地执行BGSAVE命令,Redis服务器在每次成功创建RDB文件之后,负责自动触发BGSAVE命令的时间计数器以及修改次数计数器都会被清零并重新开始计数:无论这个RDB文件是由自动触发的BGSAVE命令创建的,还是由用户执行的SAVE命令或BGSAVE命令创建的,都是如此。
RDB持久化是Redis默认使用的持久化方式,如果用户在启动Redis服务器时,既没有显式地关闭RDB持久化功能,也没有启用AOF持久化功能,那么Redis默认将使用以下save选项进行RDB持久化:
save 60 10000
save 300 100
save 3600 1
如果想关闭默认的RDB持久化行为,让Redis服务器处于完全无持久状态,那么可以在Redis配置文件提供如下配置:
save ""
使用上面的选项Redis服务器将不会再进行默认的RDB持久化,处于无持久状态的服务器在关机之后将丢失关机之前存储的所有数据,这种服务器可以用作单纯的内存缓存服务器。
选择SAVE命令还是BGSAVE命令?
SAVE命令在创建RDB文件期间会阻塞Redis服务器,如果需要在创建RDB文件期间的同时让Redis服务器继续为其他客户端服务,那么只能选择BGSAVE命令来创建RDB文件。
因为SAVE命令无须创建子进程,它不会因为创建子进程而消耗额外的内存,所以在维护离线的Redis服务器时,使用SAVE命令能够比使用BGSAVE命令更快地完成创建RDB文件的工作。
1.2 RDB的文件结构
RDB总体结构分为7个部分,如下图:
RDB文件标识符
文件最开头的部分为RDB文件标识符,这个标识符的内容为”REDIS”这5个字符。Redis服务器在尝试载入RDB文件的时候,可以通过这个标识符快速地判断该文件是否为真正的RDB文件。
●版本号
跟在RDB文件标识符之后的是RDB文件的版本号,这个版本号是一个字符串格式的数字,长度为4个字符。目前最新的RDB文件版本为第9版,因此RDB文件的版本号将为字符串”0009”。不同版本的RDB文件在结构上都会有一些不同,总的来说,新版RDB文件都会在旧版RDB文件的基础上添加更多信息,因此RDB文件的版本越新,RDB文件的结构就越复杂。
关于RDB文件,需要说明的另外一点是新版Redis服务器总是能够向下兼容旧版Redis服务器生成的RDB文件。比如,生成第9版RDB文件的Redis 5.0既能够正常读入由Redis 4.0生成的第8版RDB文件,也能够读入由Redis 3.2生成的第7版RDB文件,甚至更旧版本的RDB文件也是可以的。与此相反,如果Redis服务器生成的是较旧版本的RDB文件,那么它是无法读入更新版本的RDB文件的。比如,生成第8版RDB文件的Redis 4.0就不能读入由Redis 5.0生成的第9版RDB文件。
●设备附加信息
RDB文件的设备附加信息部分记录了生成RDB文件的Redis服务器及其所在平台的信息,比如服务器的版本号、宿主机器的架构、创建RDB文件时的时间戳、服务器占用的内存数量等。
●数据库数据
RDB文件的数据库数据部分记录了Redis服务器存储的0个或任意多个数据库的数据,当这个部分包含多数个数据库的数据时,各个数据库的数据将按照数据库号码从小到大进行排列,比如,0号数据库的数据将排在最前面,紧接着是1号数据库的数据,然后是2号数据库的数据,以此类推,例如下图。
●Lua脚本缓存
如果Redis服务器启用了复制功能,那么服务器将在RDB文件的Lua脚本缓存部分保存所有已被缓存的Lua脚本。这样一来,从服务器在载入RDB文件完成数据同步之后,就可以继续执行主服务器发来的EVALSHA命令了。
●EOF
RDB文件的EOF部分用于标识RDB正文内容的末尾,它的实际值为二进制值0xFF。当Redis服务器读取到EOF的时候,它知道RDB文件的正文部分已经全部读取完毕了。
●CRC64校验和
RDB文件的末尾是一个以无符号64位整数表示的CRC64校验和,比如5097628732947693614。Redis服务器在读入RDB文件时会通过这个校验和来快速地检查RDB文件是否有出错或者损坏的情况出现。
1.2.1 数据库信息结构
上面说到RDB文件的数据库部分包含了任意多个数据库的数据,其中每个数据都由数据库号码、键值对总数量、带有过期时间的键值对数量、键值对数据部分。如下图:
- 数据库号码:以数字的形式记录了数据的号码,例如0。Redis服务器在加载RDB文件时,会根据这个号码切换到对应的数据库,从而确保键值对会被载入正确的数据中。
- 第二和第三部分:RDB文件会使用两个数字,分别记录数据库包含的键值对总数量以及数据库中带有过期时间的键值对数量。Redis服务器将根据这两个数字,以尽可能优化的方式创建数据库的内部数据结构。
- RDB文件将以无序方式记录数据库包含的所有键值对。具体来说,数据库中的每个键值对都会被划分为最多5个部分:
每个键值对开头的第一部分记录的是可能存在的过期时间,这是一个毫秒级精度的UNIX时间戳。
之后的LRU信息或者LFU信息分别用于实现可选的LRU算法或者LFU算法,并且因为Redis只能选择一种键淘汰算法,所以这两项信息将不会同时出现,最多只会出现其中一种。至于最后三个部分则分别记录了键值对的类型(比如字符串、列表、散列等)以及键和值。
1.2.2 RDB文件载入流程
首先,当Redis服务器启动时,它会在工作目录中查找是否有RDB文件出现,如果有就打开它,然后读取文件的内容并执行以下载入操作:
1)检查文件开头的标识符是否为”REDIS”,如果是则继续执行后续的载入操作,不是则抛出错误并终止载入操作。
2)检查文件的RDB版本号,以此来判断当前Redis服务器能否读取这一版本的RDB文件。
3)根据文件中记录的设备附加信息,执行相应的操作和设置。
4)检查文件的数据库数据部分是否为空,如果不为空就执行以下子操作:
- 根据文件记录的数据库号码,切换至正确的数据库。
- 根据文件记录的键值对总数量以及带有过期时间的键值对数量,设置数据库底层数据结构。
- 一个接一个地载入文件记录的所有键值对数据,并在数据库中重建这些键值对。
5)如果服务器启用了复制功能,那么将之前缓存的Lua脚本重新载入缓存中。
6)遇到EOF标识,确认RDB正文已经全部读取完毕。
7)载入RDB文件末尾记录的CRC64校验和,把它与载入数据期间计算出的CRC64校验和进行对比,以此来判断被载入的数据是否完好无损。
8)RDB文件载入完毕,服务器开始接受客户端请求。
1.3 RDB会造成数据丢失
RDB文件记录的是服务器在开始创建文件的那一刻,服务器中包含的所有键值对数据,这种数据持久化方式通常被称为时间点快照(point-in-time snapshot)。时间点快照持久化的一个特点是,系统在停机时将丢失最后一次成功实施持久化之后的所有数据。对于一个只使用RDB持久化的Redis服务器来说,服务器停机时丢失的数据量将取决于最后一次成功执行的RDB持久化操作,以及该操作开始执行的时间。
因为Redis允许使用SAVE和BGSAVE这两种命令来执行RDB持久化操作,所以接下来将分别分析这两个命令在遭遇故障停机时的表现。
1.3.1 SAVE命令停机情况
因为SAVE命令是一个同步操作,它的开始和结束都位于同一个原子时间之内,所以如果用户使用SAVE命令进行持久化,那么服务器在停机时将丢失最后一次成功执行SAVE命令之后产生的所有数据。
时间 | 事件 | |
---|---|---|
T0 | 服务器开始运行 | |
T1 | 服务器执行 set k1 v1 | |
T2 | 服务器执行 set k2 v2 | |
T3 | 服务器执行SAVE命令,成功创建RDB文件 | |
T4 | 服务器执行 set k3 v3 | |
T5 | 服务器执行 set k4 v4 | |
T6 | 服务器执行SAVE命令,成功创建RDB文件 | |
T7 | 服务器执行 set k5 v5 | |
T8 | 服务器执行 set k6 v6 | |
T9 | 服务器停机 |
因为服务器最后一次成功执行SAVE命令是在T6,所以服务器创建的RDB文件包含k1至k4的数据在内的数据,因为最后一次执行SAVE的时间点是T6,而T9时间点出现了停机,当服务器重启时T7、T8所操作的数据(k5和k6)将会丢失,而k1至k4的数据将会被恢复。
1.3.2 BGSAVE命令停机情况
因为BGSAVE命令是一个异步命令,它的开始和结束并不位于同一个原子时间之内,所以如果用户使用BGSAVE命令进行持久化,那么服务器在停机时丢失的数据量将取决于最后一次成功执行的BGSAVE命令的开始时间。
时间 | 事件 | |
---|---|---|
T0 | 服务器开始运行 | |
T1 | 服务器执行 set k1 v1 | |
T2 | 服务器执行 set k2 v2 | |
T3 | 服务器执行BGSAVE命令,开始创建RDB文件 | |
T4 | 服务器执行 set k3 v3 | |
T5 | RDB文件创建完毕 | |
T6 | 服务器执行set k4 v4 | |
T7 | 服务器执行BGSAVE命令,开始创建RDB文件 | |
T8 | 服务器执行 set k5 v5 | |
T9 | 服务器执行 set k6 v6 | |
T10 | 服务器停机 |
- 因为T7创建的新RDB文件尚未完成,所以服务器在停机后将使用T5成功创建的RDB文件进行数据恢复。
- 虽然服务器现有的RDB文件是在T5成功创建的,但由于这个文件是T3开始创建的,所以只包含了T3之前的数据,即k1和k2的数据,其余数据将会被丢失。
2.AOF持久化
2.1 AOF介绍
与全量式的RDB持久方式不同,AOF提供的是增量式的持久化功能,这种持久化的核心原理在于:服务器每次执行完命令后,都会以协议文件的方式将被执行的命令追加到AOF文件的末尾。这样一来,服务器在停机后,只要重新执行AOF文件中保存的Redis命令,就可以将数据库恢复至停机之前的状态。AOF持久化很像MySQL的biglog(mysql的二进制日志),对比RDB持久化以某个周期创建整个RDB文件,AOF持久化将要执行的命令追加到协议文件效率更高,所需的计算资源和内存资源更少,但由于AOF持久化是日志的形式追加到协议文件,相比较RDB持久化所产生的RDB文件体积会更大。AOF文件的生成过程如下:
时间 | 事件 | AOF文件记录的命令 |
---|---|---|
T0 | 服务器启动 | (空白) |
T1 | 服务器执行命令 set k1 v1 | select 0 set k1 v1 |
T2 | 服务器执行命令 set k2 v2 | select 0 set k1 v1 set k2 v2 |
T3 | 服务器执行命令 rpush lst a b c | select 0 set k1 v1 set k2 v2 rpush lst a b c |
T4 | 服务器停机 | select 0 set k1 v1 set k2 v2 rpush lst a b c |
从上面例子可以看出,随着服务器不断执行命令,被执行的命令也会不断被保存在AOF文件中(例子中select 0切换到用户正在使用的数据库的号码,这样在还原AOF文件时就知道还原到那个数据库了)。即使服务器在T4阶段停机,服务器在重启时通过重新执行AOF文件包含的命令来恢复数据。对于上面的例子来说服务器只需执行AOF文件中包含的4个命令即可让数据库重复回到停机之前的状态。为了理解AOF文件,上面例子都是直接写出被执行的命令,但在实际的AOF文件中,被执行的命令是以Redis网络协议的方式保存的。
2.2 AOF配置
2.2.1 开启AOF持久化
打开AOF持久化功能只需在Redis的配置文件通过配置appendonly选项为yes,如果需要关闭AOF持久化设置appendonly选项为no即可。当AOF持久化功能处于打开状态时,Redis服务器在默认情况下将会创建一个名为appendonly.aof文件作为AOF文件。
#打开AOF持久化
appendonly yes
#关闭AOF持久化
#appendonly no
2.2.2 设置AOF文件冲洗频率
为了提高程序的写入性能,现代化的操作系统通常会把针对硬盘的多次写操作优化为一次写操作。具体的做法是,当程序调用write系统调用对文件进行写入时,系统并不会直接把数据写入硬盘,而是会先将数据写入位于内存的缓冲区中,等到指定的时限到达或者满足某些写入条件时,系统才会执行flush系统调用,将缓冲区中的数据冲洗至硬盘。
这种优化机制虽然提高了程序的性能,但是也给程序的写入操作带来了不确定性,特别是对于AOF这样的持久化功能来说,AOF文件的冲洗机制将直接影响AOF持久化的安全性。为了消除上述机制带来的不确定性,Redis向用户提供了appendfsync选项,以此来控制系统冲洗AOF文件的频率:
appendfsync <value>
appendfsync选项拥有always、everysec、no3个可选值,Redis使用everysec作为appendfsync选项的默认值。它们的作用如下:
- always:没执行一个命令就对AOF文件执行一次冲洗操作。在使用always值的情况下,服务器在停机时最多只会丢失一个命令的数据,但使用这种冲洗方式很消耗性能。
- everysec:每隔1s就会AOF文件执行一次冲洗操作。在使用everysec值的情况下,服务器在停机时最多只会丢失1s内产生的命令数据,这是一种兼顾性能和安全性的折中方案,Redis使用everysec作为appendfsync选项的默认值。
- no:不主动对AOF文件执行冲洗操作,由操作系统决定何时对AOF进行冲洗。在使用no值的情况下,可能丢失的数据具有不确定性。
2.2.3 AOF重写
随着服务器不断执行,被执行的命令也会越来越多,而负责记录这个命令的AOF文件体积也会越来越大。如果服务器曾经对相同的key执行过多次修改操作,那么AOF文件中还会出现大量冗余的命令,例如下面的例子:
select 0
set msg "zxp"
set msg "zxp11"
set msg "zxp22"
上面这些命令最终修改可简化为以下命令:
select 0
set msg "zxp22"
冗余的命令不仅增加了AOF文件的体积,AOF文件越来越大时Redis服务器恢复AOF文件的数据时消费的时间也会越来越多。为了减少冗余命令和AOF文件体积,提升恢复AOF文件执行速度,Redis提供了AOF重写功能,该功能能够生成一个全新的AOF文件,并且该文件只包含恢复当前数据库所需的尽可能少的命令。
开启AOF重写功能有两种方式:
(1).通过BGREWRITEAOF命令来显示地触发AOF重写操作。
(2).通过在Redis配置文件配置AOF相关选项来触发AOF重写操作。
BGREWRITEAOF:
BGREWRITEAOF命令是一个异步命令,它没有任何参数,Redis服务器在接收到该命令之后会创建一个子进程,由它扫描整个数据库并生成新的AOF文件。当新的AOF文件生成完毕,子进程就会退出并通知Redis服务器(父进程),然后Redis服务器就会使用新的AOF文件代替已有的AOF文件,借此完成整个重写操作。
关于BGREWRITEAOF还有两点需要注意:首先,如果用户发送BGREWRITEAOF命令请求时,服务器正在创建RDB文件,那么服务器将把AOF重写操作延后到RDB文件创建完毕之后再执行,从而避免两个写硬盘操作同时执行导致机器性能下降;其次,如果服务器在执行重写操作的过程中,又接收到了新的BGREWRITEAOF命令请求,那么服务器将返回以下错误:
redis> BGREWRITEAOF
(error) ERR Background append only file rewriting already in progress
AOF重写配置选项:
除了显示的使用BGREWRITEAOF命令,还可以在Redis配置文件通过设置以下两个配置选项让Redis自动触发BGREWRITEAOF命令:
auto-aof-rewrite-mini-size <value>
auto-aof-rewrite-percentage <value>
- auto-aof-rewrite-mini-size:选项用于设置触发自动AOF文件重写所需的最小AOF文件体积,当AOF文件体积小于给定值时,服务器将不会自动执行BGREWRITEAOF命令。默认情况auto-aof-rewrite-mini-size的值为64mb。配置如下,下面配置表示如果AOF文件体积小于64MB,那么将不会自动执行BGREWRITEAOF命令。
auto-aof-rewrite-percentage:此选项用于控制触发自动AOF文件重写所需的文件体积增大比例。默认情况auto-aof-rewrite-mini-size的值为100,表示如果当前AOF文件的体积比最后一次AOF文件重写之后的体积增大了一倍(100%),那么将自动执行一次BGREWRITEAOF命令。如果Redis服务器刚刚启动,还没有执行过AOF文件重写操作,那么启动服务器时使用的AOF文件的体积将被用作最后一次AOF文件重写的体积。auto-aof-rewrite-mini-size 64mb
举个例子,如果服务器启动时AOF文件的体积为200MB,而auto-aof-rewrite-percentage选项的值为100,那么当AOF文件的体积增大至超过400MB时,服务器就会自动进行一次AOF重写。与此类似,在同样设置下,如果AOF文件的体积从最后一次重写之后的300MB增大至超过600MB,那么服务器将再次执行AOF重写操作。3.RDB持久化与AOF持久化的优缺点
RDB持久化是一种全量持久化,它在创建RDB文件时需要存储整个服务器包含的所有数据,并因此消耗大量计算资源和内存资源,所以通过增大RDB文件的生成频率来保证数据安全不是一种好的方案。
优点:
(1).生成的持久化文件体积更小。使用RDB持久化的方式生成的RDB文件是一个经过压缩的二进制文件,相比较AOF持久化方式,生成的持久化文件体积更小。
(2).在恢复大数据集时速度更快,因为体积小所以Redis在恢复RDB文件时恢复数据的速度更快(相比较AOF)。
缺点:
(1).RDB持久化方式易丢失数据,RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,若创建RDB文件的期间发生故障,那么这段的所操作的数据都可能被丢失。
(2).RDB会阻塞服务器。由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。
AOF提供的是增量式的持久化功能,这种持久化的核心原理在于:服务器每次执行完命令后,都会以协议文件的方式将被执行的命令追加到AOF文件的末尾。
优点:
AOF持久化方式不易丢失数据,且持久化消耗资源相比较RDB持久化方式少很多。AOF通过协议文件追加的形式将被执行的命令追加到AOF文件末尾,即使服务器中途出现故障也只会丢失少量数据,RDB持久化以某个周期创建整个RDB文件,创建RDB文件过程会消耗大量计算、内存资源。
缺点:
(1).AOF文件体积相比较RDB文件大很多。因为AOF文件存储的是协议文件,所以它的体积会比包含相同数据、二进制格式的RDB文件要大很多,因为AOF文件体积大,所以生成AOF文件所需的时间也会比生成RDB文件所需的时间更长。
(2).RDB持久化的恢复速度比AOF持久化的恢复速度快很多。因为RDB持久化可以直接通过RDB文件恢复数据库,而AOF持久化则需要通过执行AOF文件中保存的命令来恢复数据库(RDB属于直接恢复数据库,而AOF属于间接的恢复数据库),所以RDB持久化的恢复速度比AOF持久化的恢复速度快很多,并且体积越大越明显。
4.RDB-AOF混合持久化
RDB和AOF这两种持久化方式即有优点又有缺点,为了一个折中的持久化方案,Redis在4.0版本引入了RDB-AOF混合持久化模式,这种模式是基于AOF持久化模式构建而来,如果打开了服务器的AOF持久化功能,并Redis配置文件配置了aof-use-rdb-preamble为yes即可开启RDB-AOF混合持久化模式。
aof-use-rdb-preamble yes
当使用上面命令配置时,Redis服务器在执行AOF重写时,就会像执行BGSAVE命令那样,根据数据库当前的状态生成出相应的RDB数据,并将这些数据写入新建的AOF文件中,至于那些在AOF重写开始之后执行的Redis命令,则会继续以协议文本的方式继续追加到AOF文件的末尾,即已有RDB数据的后面。
换句话说,在开启了RDB-AOF混合持久化功能之后,服务器生成的AOF文件将由两个部分组成,其中位于AOF文件开头的是RDB格式的数据,而跟在RDB数据后面的则是AOF格式的数据。
当一个支持RDB-AOF混合持久化模式的Redis服务器启动并载入AOF文件时,它会检查AOF文件的开头是否包含了RDB格式的内容:
●如果包含,那么服务器就会先载入开头的RDB数据,然后再载入之后的AOF数据。
●如果AOF文件只包含AOF数据,那么服务器将直接载入AOF数据。
通过使用RDB-AOF混合持久化功能,用户可以同时获得RDB持久化和AOF持久化的优点:服务器既可以通过AOF文件包含的RDB数据来实现快速的数据恢复操作,又可以通过AOF文件包含的AOF数据来将丢失数据的时间窗口限制在1s之内。
需要注意的是,因为RDB-AOF混合持久化生成的AOF文件会同时包含RDB格式的数据和AOF格式的数据,而传统的AOF持久化只会生成包含AOF格式的数据,所以为了避免全新的RDB-AOF混合持久化功能给传统的AOF持久化功能使用者带来困惑,Redis目前默认是没有打开RDB-AOF混合持久化功能的:
aof-use-rdb-preamble no
但是Redis的作者声称,RDB-AOF混合持久化将在未来取代传统的RDB持久化成为Redis默认的持久化模式。
5.总结
1.Redis主要提供RDB和AOF两种持久化方式,Redis使用RDB持久化作为默认持久化功能。RDB持久化方式能够在指定的时间间隔能对数据进行快照存储。RDB持久化功能会创建一个经过压缩的二进制快照文件。
2.AOF持久化方式其工作原理是将执行完毕的命令以协议文本的方式追加到AOF文件末尾,当执行的命令越来越多时AOF文件体积也会越来越大,但向AOF文件末尾追加执行完毕的命令的所占开销相比较RDB持久化方式低。
3.RDB会阻塞服务器。由于RDB是通过父进程fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。
4.RDB持久化的优缺点:
优点:
(1).RDB持久化生成的RDB文件体积相比较AOF持久化生成的AOF文件小。因为AOF持久化是通过协议文本追加的形式将执行的命令追加到AOF文件末尾,追加命令越多AOF文件体积越大(AOF文件可能存在大量冗余命令)。而RDB持久化生成的RDB文件是经过压缩的二进制文件,所以体积相比较AOF文件要小很多。
(2).RDB持久化相比较AOF持久化恢复速度快。因为RDB文件体积比AOF体积小很多所以恢复速度也会快很多,尤其是在体积特别明显的情况下。
缺点:
- (1).RDB持久化易丢失数据。RDB持久化方式能够在指定的时间间隔能对数据进行快照存储,所以会导致部分数据丢失。
- (2).RDB持久化会阻塞服务器。由于RDB是通过父进程fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。而且RDB持久化生成RDB文件相比较AOF持久化生成AOF文件开销高很多。
5.AOF持久化的优缺点:
优点:
(1).不易丢失数据。AOF持久化是通过协议文本追加的形式将执行的命令追加到AOF文件末尾,所以不易丢失数据。
(2).创建AOF文件无需大量开销。
缺点:
(1).AOF文件体积相比较RDB文件大很多。因为AOF文件存储的是协议文件,所以它的体积会比包含相同数据、二进制格式的RDB文件要大很多,因为AOF文件体积大,所以生成AOF文件所需的时间也会比生成RDB文件所需的时间更长。
(2).RDB持久化的恢复速度比AOF持久化的恢复速度快很多。因为RDB持久化可以直接通过RDB文件恢复数据库,而AOF持久化则需要通过执行AOF文件中保存的命令来恢复数据库(RDB属于直接恢复数据库,而AOF属于间接的恢复数据库),所以RDB持久化的恢复速度比AOF持久化的恢复速度快很多,并且体积越大越明显。
6.如果即想拥有RDB的优点又想拥有AOF的优点,那么RDB-AOF混合持久化是一种折中方案。首先要开启AOF持久化功能,然后在Redis配置文件中将aof-use-rdb-preamble选线设置为yes,Redis默认设置为no。