Open superleeyom opened 3 years ago
Redis 的持久化指的是把内存中存储的数据以文件形式存储到硬盘上,而服务器也可以根据这些文件在系统停机之后实施数据恢复,让服务器的数据库重新回到停机之前的状态。为了满足不同的持久化需求,Redis 提供了RDB持久化、AOF持久化和RDB-AOF混合持久化等多种持久化方式以供用户选择。如果用户有需要,也可以完全关闭持久化功能,让服务器处于无持久化状态。
RDB持久化
AOF持久化
RDB-AOF混合持久化
无持久化状态
RDB 的全称是 Redis DataBase,RDB持久化是 Redis 默认使用的持久化功能,通过创建以.rdb后缀结尾的二进制文件,该文件包含了服务器在各个数据库中存储的键值对数据等信息。Redis 提供了三种创建 RDB 文件的方法,分别是:手动执行SAVE命令、手动执行BGSAVE命令、通过配置选项自动创建等三种方式。
RDB
Redis DataBase
.rdb
SAVE命令
BGSAVE命令
那 RDB 文件的结构是咋样的呢?它由如下几部分组成:
Redis 服务器载入 RDB 文件的整体流程:打开 RDB 文件 --> 检查文件头 --> 检查版本号 --> 读取设备信息 --> 重建数据库 --> 重建脚本缓存 --> 对比校验和 --> 数据载入完毕。
可以通过SAVE命令,以同步方式创建出一个记录了服务器当前所有数据库数据的 RDB 文件。SVAE命令是一个无参数命令,创建成功后,返回 OK 提示:
SAVE
SVAE
redis> SAVE OK
由于是同步方式进行创建的 RDB 文件,那在SAVE命令执行期间,Redis 服务器将阻塞,直到RDB文件创建完毕为止。如果 Redis 服务器在执行SAVE命令时已经拥有了相应的 RDB 文件,那么服务器将使用新创建的 RDB 文件代替已有的 RDB 文件。
那BGSAVE其实就是解决SAVE命令的阻塞问题的,它与SAVE命令的不同之处在于,BGSAVE命令是异步执行的,BGSAVE不会直接使用 Redis 服务器进程创建 RDB文件,而是使用子进程创建 RDB 文件。
BGSAVE
redis> BGSAVE Background saving started
用户执行BGSAVE命令,Redis 的整个执行流程如下:
虽然说BGSAVE命令是异步执行的,Redis 服务器在BGSAVE命令执行期间仍然可以继续处理其他客户端发送的命令请求,不会阻塞服务器,但由于执行BGSAVE命令需要创建子进程,所以父进程占用的内存数量越大,创建子进程这一操作耗费的时间也会越长,因此 Redis 服务器在执行BGSAVE命令时,仍然可能会由于创建子进程而被短暂地阻塞。
除了手动执行BGSAVE和SAVE命令创建RDB文件外,Redis 还支持通过配置选项自动创建 RDB 文件:
save <seconds> <changes>
对于 seconds 和 changes 参数,可以这么理解:如果服务器在 seconds 秒之内,对其包含的各个数据库总共执行了至少 changes 次修改,那么服务器将自动执行一次BGSAVE命令。
seconds
changes
当用户向 Redis 服务器提供多个 save 选项,只要满足其中任意一个选项,就会自动执行一次BGSAVE命令。
save 6000 1 save 6000 10 save 6000 100
为了避免因满足条件,而频繁触发执行BGSAVE命令,Redis 服务器在每次成功创建 RDB 文件之后,负责自动触发BGSAVE命令的时间计数器以及修改次数计数器都会被清零并重新开始计数。
无论用户使用的是SAVE命令还是BGSAVE命令,停机时服务器丢失的数据量将取决于创建 RDB 文件的时间间隔:间隔越长,停机时丢失的数据也就越多。
RDB 持久化是一种全量持久化操作,它在创建 RDB 文件时需要存储整个服务器包含的所有数据,并因此消耗大量计算资源和内存资源,所以用户是不太可能通过增大 RDB 文件的生成频率来保证数据安全的。
从 RDB 持久化的特征来看,它更像是一种数据备份手段而非一种普通的数据持久化手段。为了解决 RDB 持久化在停机时可能会丢失大量数据这一问题,并提供一种真正符合用户预期的持久化功能,Redis 推出 AOF 持久化模式。
与全量式的 RDB 持久化功能不同,AOF 提供的是增量式的持久化功能,这种持久化的核心原理在于:服务器每次执行完写命令之后,都会以协议文本的方式将被执行的命令追加到 AOF 文件的末尾。这样一来,服务器在停机之后,只要重新执行 AOF 文件中保存的 Redis 命令,就可以将数据库恢复至停机之前的状态,有点像 MySQL 的 binlog。
binlog
SET K1 V1
SET K2 V2
随着服务器不断地执行命令,被执行的命令也会不断地被保存到 AOF 文件中。其实在实际的 AOF 文件中,命令都是以 Redis 网络协议的方式保存的,比如:
*2\r\n$6\r\nSELECT\r\n$1\r\n0\r\n *3\r\n$3\r\nSET\r\n$2\r\nk1\r\n$2\r\nv1\r\n *3\r\n$3\r\nSET\r\n$2\r\nk2\r\n$2\r\nv2\r\n
Redis 服务器执行:
appendonly yes:开启 AOF 持久化功能,Redis 服务器在默认情况下将创建一个名为appendonly.aof的文件作为AOF 文件。
appendonly yes
appendonly.aof
appendonly no:关闭 AOF 持久化功能。
appendonly no
为了提高程序的写入性能,现代化的操作系统通常会把针对硬盘的多次写操作优化为一次写操作。当程序调用 write 系统对文件进行写入时,系统并不会直接把数据写入硬盘,而是会先将数据写入位于内存的缓冲区中,等到指定的时限到达或者满足某些写入条件时,系统才会执行 flush 系统调用,将缓冲区中的数据冲洗至硬盘。
Redis 向用户提供了appendfsync选项,以此来控制系统冲洗 AOF 文件的频率:
appendfsync
appendfsync <value>
通常有三个可选值,分别是:
always
everysec
no
所以 Redis 使用everysec作为appendfsync选项的默认值。除非有明确的需求,否则用户不应该随意修改appendfsync选项的值。
随着服务器不断运行,被执行的命令将变得越来越多,而负责记录这些命令的 AOF 文件也会变得越来越大。与此同时,如果服务器曾经对相同的键执行过多次修改操作,那么 AOF 文件中还会出现多个冗余命令。
SELECT 0 SET msg "hello world! " SET msg "good morning! " SET msg "happy birthday! " SADD fruits "apple" SADD fruits "banana" SADD fruits "cherry" SADD fruits "dragon fruit" SREM fruits "dragon fruit" SADD fruits "durian" RPUSH job-queue 10086
以上命令,重写后最终可以简化为:
SELECT 0 SET msg "happy birthday! " SADD fruits "apple" "banana" "cherry" "durian" RPUSH job-queue 10086
为了减少冗余命令,让 AOF 文件保持“苗条”,并提供数据恢复操作的执行速度,Redis 提供了 AOF 重写功能BGREWRITEAOF命令,该命令能够生成一个全新的 AOF 文件,并且文件中只包含恢复当前数据库所需的尽可能少的命令。
BGREWRITEAOF
与 RDB 持久化的 BGSAVE命令一样,BGREWRITEAOF命令也是一个异步命令,Redis 服务器在接收到该命令之后会创建出一个子进程,由它扫描整个数据库并生成新的 AOF 文件。当新的 AOF 文件生成完毕,子进程就会退出并通知 Redis 服务器(父进程),然后 Redis 服务器就会使用新的 AOF 文件代替已有的 AOF 文件,借此完成整个重写操作。
除了手动执行BGREWRITEAOF命令,也可以通过配置自动触发BGREWRITEAOF命令:
auto-aof-rewrite-min-size <value>:选项用于设置触发自动 AOF 文件重写所需的最小 AOF 文件体积,当 AOF 文件的体积大于给定值时,服务器将自动执行BGREWRITEAOF命令,该值的默认值是 64mb。
auto-aof-rewrite-min-size <value>
auto-aof-rewrite-percentage <value>:它控制的是触发自动 AOF 文件重写所需的文件体积增大比例。举个例子,如果此值设置为 100,表示如果当前 AOF 文件的体积比最后一次 AOF 文件重写之后的体积增大了一倍(100%),那么将自动执行一次BGREWRITEAOF命令。
auto-aof-rewrite-percentage <value>
优点:
缺点:
由于 RDB 持久化和 AOF 持久化都有各自的优缺点,因此在很长一段时间里,如何选择合适的持久化方式成了很多 Redis 用户面临的一个难题。为了解决这个问题,Redis 从 4.0 版本开始引入 RDB-AOF 混合持久化模式,这种模式是基于 AOF 持久化模式构建而来的,如果用户打开了服务器的 AOF 持久化功能,并且将
aof-use-rdb-preamble <value>
设置为 yes,那么 Redis 服务器在执行 AOF 重写操作时,就会像执行BGSAVE命令那样,根据数据库当前的状态生成出相应的 RDB 数据,并将这些数据写入新建的 AOF 文件中,至于那些在 AOF 重写(BGREWRITEAOF)开始之后执行的 Redis 命令,则会继续以协议文本的方式追加到新 AOF 文件的末尾,即已有的 RDB 数据的后面。
所以,开启了 RDB-AOF 混合持久化后,服务器生成的 AOF 文件将由两个部分组成,其中位于 AOF 文件开头的是 RDB 格式的数据,而跟在 RDB 数据后面的则是 AOF 格式的数据。
当一个支持 RDB-AOF 混合持久化模式的 Redis 服务器启动并载入 AOF 文件时,它会检查 AOF 文件的开头是否包含了 RDB 格式的内容:
所以为了避免全新的 RDB-AOF 混合持久化功能给传统的 AO F持久化功能使用者带来困惑,Redis 目前默认是没有打开 RDB-AOF 混合持久化功能的:aof-use-rdb-preamble no,如果要开启,需要用户手动设置 value 为 yes。
aof-use-rdb-preamble no
即使用户没有显式地开启 RDB 持久化功能和 AOF 持久化功能,Redis 服务器也会默认使用以下配置进行 RDB 持久化:
save 6010000 save 300100 save 3600 1
如果用户想要彻底关闭这一默认的 RDB 持久化行为,让 Redis 服务器处于完全的无持久化状态,那么可以在服务器启动时向它提供以下配置选项:
save ""
这样一来,服务器将不会再进行默认的 RDB 持久化,从而使得服务器处于完全的无持久化状态中。处于这一状态的服务器在关机之后将丢失关机之前存储的所有数据,这种服务器可以用作单纯的内存缓存服务器。
如何优雅的关闭 Redis 服务器呢?那就是使用 SHUTDOWN命令,执行该命令,将执行如下动作:
SHUTDOWN
所以只要服务器启用了持久化功能,那么使用SHUTDOWN命令来关闭服务器就不会造成任何数据丢失。SHUTDOWN命令提供的 save 选项或者nosave 选项,显式地指示服务器在关闭之前是否需要执行持久化操作:
save
nosave
SHUTDOWN [save|nosave]
如果用户给定的是 save 选项,那么无论服务器是否启用了持久化功能,服务器都会在关闭之前执行一次持久化操作。如果用户给定的是 nosave选项,那么服务器将不执行持久化操作,直接关闭服务器。在这种情况下,如果服务器在关闭之前曾经修改过数据库,那么它将丢失那些尚未保存的数据。
总的来说,在数据持久化这个问题上,Redis 4.0 及之后版本的使用者都应该优先使用 RDB-AOF 混合持久化;对于 Redis 4.0 之前版本的使用者,因为 RDB 持久化更接近传统意义上的数据备份功能,而 AOF 持久化则更接近于传统意义上的数据持久化功能,所以如果用户不知道自己具体应该使用哪种持久化功能,那么可以优先选用 AOF 持久化作为数据持久化手段,并将 RDB 持久化用作辅助的数据备份手段。
Redis 的持久化指的是把内存中存储的数据以文件形式存储到硬盘上,而服务器也可以根据这些文件在系统停机之后实施数据恢复,让服务器的数据库重新回到停机之前的状态。为了满足不同的持久化需求,Redis 提供了
RDB持久化
、AOF持久化
和RDB-AOF混合持久化
等多种持久化方式以供用户选择。如果用户有需要,也可以完全关闭持久化功能,让服务器处于无持久化状态
。RDB持久化
RDB
的全称是Redis DataBase
,RDB持久化
是 Redis 默认使用的持久化功能,通过创建以.rdb
后缀结尾的二进制文件,该文件包含了服务器在各个数据库中存储的键值对数据等信息。Redis 提供了三种创建 RDB 文件的方法,分别是:手动执行SAVE命令
、手动执行BGSAVE命令
、通过配置选项自动创建等三种方式。那 RDB 文件的结构是咋样的呢?它由如下几部分组成:
Redis 服务器载入 RDB 文件的整体流程:打开 RDB 文件 --> 检查文件头 --> 检查版本号 --> 读取设备信息 --> 重建数据库 --> 重建脚本缓存 --> 对比校验和 --> 数据载入完毕。
SAVE命令
可以通过
SAVE
命令,以同步方式创建出一个记录了服务器当前所有数据库数据的 RDB 文件。SVAE
命令是一个无参数命令,创建成功后,返回 OK 提示:由于是同步方式进行创建的 RDB 文件,那在
SAVE
命令执行期间,Redis 服务器将阻塞,直到RDB文件创建完毕为止。如果 Redis 服务器在执行SAVE
命令时已经拥有了相应的 RDB 文件,那么服务器将使用新创建的 RDB 文件代替已有的 RDB 文件。BGSAVE命令
那
BGSAVE
其实就是解决SAVE
命令的阻塞问题的,它与SAVE
命令的不同之处在于,BGSAVE
命令是异步执行的,BGSAVE
不会直接使用 Redis 服务器进程创建 RDB文件,而是使用子进程创建 RDB 文件。用户执行
BGSAVE
命令,Redis 的整个执行流程如下:SAVE
命令,创建新的RDB文件虽然说
BGSAVE
命令是异步执行的,Redis 服务器在BGSAVE
命令执行期间仍然可以继续处理其他客户端发送的命令请求,不会阻塞服务器,但由于执行BGSAVE
命令需要创建子进程,所以父进程占用的内存数量越大,创建子进程这一操作耗费的时间也会越长,因此 Redis 服务器在执行BGSAVE
命令时,仍然可能会由于创建子进程而被短暂地阻塞。通过配置选项自动创建RDB文件
除了手动执行
BGSAVE
和SAVE
命令创建RDB文件外,Redis 还支持通过配置选项自动创建 RDB 文件:对于
seconds
和changes
参数,可以这么理解:如果服务器在seconds
秒之内,对其包含的各个数据库总共执行了至少changes
次修改,那么服务器将自动执行一次BGSAVE
命令。当用户向 Redis 服务器提供多个 save 选项,只要满足其中任意一个选项,就会自动执行一次
BGSAVE
命令。为了避免因满足条件,而频繁触发执行
BGSAVE
命令,Redis 服务器在每次成功创建 RDB 文件之后,负责自动触发BGSAVE
命令的时间计数器以及修改次数计数器都会被清零并重新开始计数。RDB 持久化的缺陷
无论用户使用的是
SAVE
命令还是BGSAVE
命令,停机时服务器丢失的数据量将取决于创建 RDB 文件的时间间隔:间隔越长,停机时丢失的数据也就越多。RDB 持久化是一种全量持久化操作,它在创建 RDB 文件时需要存储整个服务器包含的所有数据,并因此消耗大量计算资源和内存资源,所以用户是不太可能通过增大 RDB 文件的生成频率来保证数据安全的。
从 RDB 持久化的特征来看,它更像是一种数据备份手段而非一种普通的数据持久化手段。为了解决 RDB 持久化在停机时可能会丢失大量数据这一问题,并提供一种真正符合用户预期的持久化功能,Redis 推出 AOF 持久化模式。
AOF持久化
与全量式的 RDB 持久化功能不同,AOF 提供的是增量式的持久化功能,这种持久化的核心原理在于:服务器每次执行完写命令之后,都会以协议文本的方式将被执行的命令追加到 AOF 文件的末尾。这样一来,服务器在停机之后,只要重新执行 AOF 文件中保存的 Redis 命令,就可以将数据库恢复至停机之前的状态,有点像 MySQL 的
binlog
。SET K1 V1
SET K1 V1
SET K2 V2
SET K1 V1
SET K2 V3
随着服务器不断地执行命令,被执行的命令也会不断地被保存到 AOF 文件中。其实在实际的 AOF 文件中,命令都是以 Redis 网络协议的方式保存的,比如:
Redis 服务器执行:
appendonly yes
:开启 AOF 持久化功能,Redis 服务器在默认情况下将创建一个名为appendonly.aof
的文件作为AOF 文件。appendonly no
:关闭 AOF 持久化功能。设置 AOF 文件冲洗频率
为了提高程序的写入性能,现代化的操作系统通常会把针对硬盘的多次写操作优化为一次写操作。当程序调用 write 系统对文件进行写入时,系统并不会直接把数据写入硬盘,而是会先将数据写入位于内存的缓冲区中,等到指定的时限到达或者满足某些写入条件时,系统才会执行 flush 系统调用,将缓冲区中的数据冲洗至硬盘。
Redis 向用户提供了
appendfsync
选项,以此来控制系统冲洗 AOF 文件的频率:通常有三个可选值,分别是:
always
:每执行一个写命令,就对 AOF 文件执行一次冲洗操作。如果服务器停机,此时最多只会丢失一个命令的数据,但使用这种冲洗方式将使 Redis 服务器的性能降低至传统关系数据库的水平。everysec
:每隔 1s,就对 AOF 文件执行一次冲洗操作。服务器在停机时最多只会丢失 1s 之内产生的命令数据,这是一种兼顾性能和安全性的折中方案。no
:不主动对 AOF 文件执行冲洗操作,由操作系统决定何时对 AOF 进行冲洗。服务器在停机时将丢失系统最后一次冲洗 AOF 文件之后产生的所有命令数据,至于数据量的具体大小则取决于系统冲洗 AOF 文件的频率。所以 Redis 使用
everysec
作为appendfsync
选项的默认值。除非有明确的需求,否则用户不应该随意修改appendfsync
选项的值。AOF 重写
随着服务器不断运行,被执行的命令将变得越来越多,而负责记录这些命令的 AOF 文件也会变得越来越大。与此同时,如果服务器曾经对相同的键执行过多次修改操作,那么 AOF 文件中还会出现多个冗余命令。
以上命令,重写后最终可以简化为:
为了减少冗余命令,让 AOF 文件保持“苗条”,并提供数据恢复操作的执行速度,Redis 提供了 AOF 重写功能
BGREWRITEAOF
命令,该命令能够生成一个全新的 AOF 文件,并且文件中只包含恢复当前数据库所需的尽可能少的命令。与 RDB 持久化的
BGSAVE
命令一样,BGREWRITEAOF
命令也是一个异步命令,Redis 服务器在接收到该命令之后会创建出一个子进程,由它扫描整个数据库并生成新的 AOF 文件。当新的 AOF 文件生成完毕,子进程就会退出并通知 Redis 服务器(父进程),然后 Redis 服务器就会使用新的 AOF 文件代替已有的 AOF 文件,借此完成整个重写操作。除了手动执行
BGREWRITEAOF
命令,也可以通过配置自动触发BGREWRITEAOF
命令:auto-aof-rewrite-min-size <value>
:选项用于设置触发自动 AOF 文件重写所需的最小 AOF 文件体积,当 AOF 文件的体积大于给定值时,服务器将自动执行BGREWRITEAOF
命令,该值的默认值是 64mb。auto-aof-rewrite-percentage <value>
:它控制的是触发自动 AOF 文件重写所需的文件体积增大比例。举个例子,如果此值设置为 100,表示如果当前 AOF 文件的体积比最后一次 AOF 文件重写之后的体积增大了一倍(100%),那么将自动执行一次BGREWRITEAOF
命令。AOF 持久化的优缺点
优点:
everysec
选项,用户可以将数据丢失的时间窗口限制在 1s 之内。缺点:
BGREWRITEAOF
命令与 RDB 持久化使用的BGSAVE
命令一样都需要创建子进程,所以在数据库体积较大的情况下,进行 AOF 文件重写将占用大量资源,并导致服务器被短暂地阻塞。RDB-AOF 混合持久化
由于 RDB 持久化和 AOF 持久化都有各自的优缺点,因此在很长一段时间里,如何选择合适的持久化方式成了很多 Redis 用户面临的一个难题。为了解决这个问题,Redis 从 4.0 版本开始引入 RDB-AOF 混合持久化模式,这种模式是基于 AOF 持久化模式构建而来的,如果用户打开了服务器的 AOF 持久化功能,并且将
设置为 yes,那么 Redis 服务器在执行 AOF 重写操作时,就会像执行
BGSAVE
命令那样,根据数据库当前的状态生成出相应的 RDB 数据,并将这些数据写入新建的 AOF 文件中,至于那些在 AOF 重写(BGREWRITEAOF
)开始之后执行的 Redis 命令,则会继续以协议文本的方式追加到新 AOF 文件的末尾,即已有的 RDB 数据的后面。所以,开启了 RDB-AOF 混合持久化后,服务器生成的 AOF 文件将由两个部分组成,其中位于 AOF 文件开头的是 RDB 格式的数据,而跟在 RDB 数据后面的则是 AOF 格式的数据。
当一个支持 RDB-AOF 混合持久化模式的 Redis 服务器启动并载入 AOF 文件时,它会检查 AOF 文件的开头是否包含了 RDB 格式的内容:
所以为了避免全新的 RDB-AOF 混合持久化功能给传统的 AO F持久化功能使用者带来困惑,Redis 目前默认是没有打开 RDB-AOF 混合持久化功能的:
aof-use-rdb-preamble no
,如果要开启,需要用户手动设置 value 为 yes。无持久化
即使用户没有显式地开启 RDB 持久化功能和 AOF 持久化功能,Redis 服务器也会默认使用以下配置进行 RDB 持久化:
如果用户想要彻底关闭这一默认的 RDB 持久化行为,让 Redis 服务器处于完全的无持久化状态,那么可以在服务器启动时向它提供以下配置选项:
这样一来,服务器将不会再进行默认的 RDB 持久化,从而使得服务器处于完全的无持久化状态中。处于这一状态的服务器在关机之后将丢失关机之前存储的所有数据,这种服务器可以用作单纯的内存缓存服务器。
优雅的关闭 Redis 服务器
如何优雅的关闭 Redis 服务器呢?那就是使用
SHUTDOWN
命令,执行该命令,将执行如下动作:所以只要服务器启用了持久化功能,那么使用
SHUTDOWN
命令来关闭服务器就不会造成任何数据丢失。SHUTDOWN
命令提供的save
选项或者nosave
选项,显式地指示服务器在关闭之前是否需要执行持久化操作:如果用户给定的是
save
选项,那么无论服务器是否启用了持久化功能,服务器都会在关闭之前执行一次持久化操作。如果用户给定的是nosave
选项,那么服务器将不执行持久化操作,直接关闭服务器。在这种情况下,如果服务器在关闭之前曾经修改过数据库,那么它将丢失那些尚未保存的数据。总结
总的来说,在数据持久化这个问题上,Redis 4.0 及之后版本的使用者都应该优先使用 RDB-AOF 混合持久化;对于 Redis 4.0 之前版本的使用者,因为 RDB 持久化更接近传统意义上的数据备份功能,而 AOF 持久化则更接近于传统意义上的数据持久化功能,所以如果用户不知道自己具体应该使用哪种持久化功能,那么可以优先选用 AOF 持久化作为数据持久化手段,并将 RDB 持久化用作辅助的数据备份手段。