05、Redis持久化规则之RDB及AOF

Redis 持久化

redis是一个内存数据库,数据保存在内存中,但是我们都知道内存的数据变化是很快的,也容易发生丢失。幸好Redis还为我们提供了持久化的机制,分别是RDB(Redis DataBase)和AOF(Append Only File)。

RDB

概念

RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘。也是默认的持久化方式,这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。

如何触发RDB持久化

对于RDB来说,提供了三种机制:save、bgsave、自动触发。

save命令

Redis Save 命令执行一个同步保存操作,将当前 Redis 实例的所有数据快照(snapshot)以 RDB 文件的形式保存到硬盘。文件位置为:/dump.rdb。

执行save命令后会阻塞服务端进程,直到RDB文件创建完毕为止,在整个RDB文件生成过程中服务器不能处理任何命令请求,所以一般情况下我们不会使用save命令触发rdb持久化。
 

127.0.0.1:6379> save
OK

bgsave命令

bgsave时Redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短。基本上 Redis 内部所有的RDB操作都是采用 bgsave 命令。

后台保存DB。会立即返回 OK 状态码。 Redis forks, 父进程继续提供服务以供客户端调用,子进程将DB数据保存到磁盘然后退出。如果操作成功,可以通过客户端命令LASTSAVE来检查操作结果

127.0.0.1:6379> bgsave
Background saving started
127.0.0.1:6379> lastsave
(integer) 1620784097

 

自动触发

自动触发是由redis配置文件来完成的。位于redis.conf配置文件中SNAPSHOTTING模块下。

save

格式:save seconds changes;

save 3600 1
save 300 100
save 60 10000

1、 “save36001”表示如果3600秒内至少1个key发生变化(新增、修改和删除),则重写rdb文件;
2、 “save300100”表示如果每300秒内至少100个key发生变化(新增、修改和删除),则重写rdb文件;
3、 “save6010000”表示如果每60秒内至少10000个key发生变化(新增、修改和删除),则重写rdb文件;

不设置save指令,或者给save传入空字符串会禁用。

stop-writes-on-bgsave-error

默认值为yes。当启用了RDB且最后一次后台保存数据失败,Redis是否停止接收数据。这会让用户意识到数据没有正确持久化到磁盘上,否则没有人会注意到灾难(disaster)发生了。如果Redis重启了,那么又可以重新开始接收数据了

rdbcompression

默认值是yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。

rdbchecksum

默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。

dbfilename

设置快照的文件名,默认是 dump.rdb。

rdb-del-sync-files

在未启用持久性的实例中删除复制使用的RDB文件。

dir

设置快照文件的存放路径,这个配置项一定是个目录,而不能是文件名。

RDB备份还原

# 备份
127.0.0.1:6379> bgsave
Background saving started
127.0.0.1:6379> lastsave 
(integer) 1620786747
# 删除内存中的数据
127.0.0.1:6379> flushdb 
OK
# 查看备份文件位置
127.0.0.1:6379> config get dir
1) "dir"
2) "/"
# 上传备份文件到需要还原的Redis的备份文件位置
# 启动redis,备份数据会直接加载
# 可以写成脚本定时执行备份

RDB持久化优缺点

优势

1、 RDB是一个非常紧凑的文件,它保存了某个时间点得数据集,非常适用于数据集的备份,比如你可以在每个小时报保存一下过去24小时内的数据,同时每天保存过去30天的数据,这样即使出了问题你也可以根据需求恢复到不同版本的数据集.;
2、 RDB是一个紧凑的单一文件,很方便传送到另一个远端数据中心或者亚马逊的S3(可能加密),非常适用于灾难恢复.;
3、 RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能.;
4、 与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些.;

劣势

1、 如果你希望在redis意外停止工作(例如电源中断)的情况下丢失的数据最少的话,那么RDB不适合你.虽然你可以配置不同的save时间点(例如每隔5分钟并且对数据集有100个写的操作),是Redis要完整的保存整个数据集是一个比较繁重的工作,你通常会每隔5分钟或者更久做一次完整的保存,万一在Redis意外宕机,你可能会丢失几分钟的数据.;
2、 RDB需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求.如果数据集巨大并且CPU性能不是很好的情况下,这种情况会持续1秒,AOF也需要fork,但是你可以调节重写日志文件的频率来提高数据集的耐久度.;

AOF

简介

以日志的形式来记录每个写操作(增量保存),将Redis执行过的所有写指令记录下来(读操作不记录), 只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。

AOF持久化流程

 

1、 客户端的请求写命令会被append追加到AOF缓冲区内;
2、 AOF缓冲区根据AOF持久化策略[always,everysec,no]将操作sync同步到磁盘的AOF文件中;
3、 AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量;
4、 Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的;

配置项

位于redis.conf中APPEND ONLY MODE模块。

AOF和RDB同时开启,系统默认取AOF的数据(数据不会存在丢失)。

appendonly

默认为no,是否开启AOF

appendfilename

默认为"appendonly.aof",AOP快照文件名

appendfsync

默认为everysec,AOF同步频率设置:

  • everysec: 每秒同步,每秒记入日志一次,如果宕机,本秒的数据可能丢失。
  • always:始终同步,每次Redis的写入都会立刻记入日志;性能较差但数据完整性比较好。
  • no:redis不主动进行同步,把同步时机交给操作系统。

Rewrite压缩

AOF采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制, 当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩, 只保留可以恢复数据的最小指令集.可以使用命令bgrewriteaof。

AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),redis4.0版本后的重写,是指上就是把rdb 的快照,以二级制的形式附在新的aof头部,作为已有的历史数据,替换掉原来的流水账操作。

Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。

重写虽然可以节约大量磁盘空间,减少恢复时间。但是每次重写还是有一定的负担的,因此设定Redis要满足一定条件才会进行重写。

no-appendfsync-on-rewrite

默认为no,还是会把数据往磁盘里刷,但是遇到重写操作,可能会发生阻塞。(数据安全,但是性能降低)。

如果yes ,不写入aof文件只写入缓存,用户请求不会阻塞,但是在这段时间如果宕机会丢失这段时间的缓存数据。(降低数据安全性,提高性能)。

auto-aof-rewrite-percentage

默认100,设置重写的基准值,文件达到100%时开始重写(文件是原来重写后文件的2倍时触发)。

auto-aof-rewrite-min-size

默认64,设置重写的基准值,最小文件64MB。达到这个值开始重写。

aof-load-truncated

默认yes,指redis在恢复时,会忽略最后一条可能存在问题的指令。默认值yes。即在aof写入时,可能存在指令写错的问题(突然断电,写了一半),这种情况下,yes会log并继续,而no会直接恢复失败。

aof-use-rdb-preamble

默认yes,混合持久化就是同时结合RDB持久化以及AOF持久化混合写入AOF文件。这样做的好处是可以结合 rdb 和 aof 的优点, 快速加载同时避免丢失过多的数据,缺点是 aof 里面的 rdb 部分就是压缩格式不再是 aof 格式,可读性差。

AOP优缺点

AOF 优点

1、 使用AOF会让你的Redis更加耐久:你可以使用不同的fsync策略:无fsync,每秒fsync,每次写的时候fsync.使用默认的每秒fsync策略,Redis的性能依然很好(fsync是由后台线程进行处理的,主线程会尽力处理客户端请求),一旦出现故障,你最多丢失1秒的数据.;
2、 AOF文件是一个只进行追加的日志文件,所以不需要写入seek,即使由于某些原因(磁盘空间已满,写的过程中宕机等等)未执行完整的写入命令,你也也可使用redis-check-aof工具修复这些问题.;
3、 Redis可以在AOF文件体积变得过大时,自动地在后台对AOF进行重写:重写后的新AOF文件包含了恢复当前数据集所需的最小命令集合整个重写操作是绝对安全的,因为Redis在创建新AOF文件的过程中,会继续将命令追加到现有的AOF文件里面,即使重写过程中发生停机,现有的AOF文件也不会丢失而一旦新AOF文件创建完毕,Redis就会从旧AOF文件切换到新AOF文件,并开始对新AOF文件进行追加操作;
4、 AOF文件有序地保存了对数据库执行的所有写入操作,这些写入操作以Redis协议的格式保存,因此AOF文件的内容非常容易被人读懂,对文件进行分析(parse)也很轻松导出(export)AOF文件也非常简单:举个例子,如果你不小心执行了FLUSHALL命令,但只要AOF文件未被重写,那么只要停止服务器,移除AOF文件末尾的FLUSHALL命令,并重启Redis,就可以将数据集恢复到FLUSHALL执行之前的状态;

AOF 缺点

1、 对于相同的数据集来说,AOF文件的体积通常要大于RDB文件的体积;
2、 根据所使用的fsync策略,AOF的速度可能会慢于RDB在一般情况下,每秒fsync的性能依然非常高,而关闭fsync可以让AOF的速度和RDB一样快,即使在高负荷之下也是如此不过在处理巨大的写入载入时,RDB可以提供更有保证的最大延迟时间(latency);

如何选择使用哪种持久化方式?

一般来说, 如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。

如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。

有很多用户都只使用 AOF 持久化, 但我们并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快, 除此之外, 使用 RDB 还可以避免之前提到的 AOF 程序的 bug 。

Note: 因为以上提到的种种原因, 未来我们可能会将 AOF 和 RDB 整合成单个持久化模型。 (这是一个长期计划。)