Redis:数据持久化

  redis作为一个高性能的key-value数据库,很大程度依赖于其基于内存的数据操作。正因其数据存放在内存中,若遇到服务异常退出、宕机等情况,无法将其数据进行恢复。好在redis为我们提供了数据持久化方案,以解决上述问题。

  redis在4.0版本之前提供两种数据持久化方案,分别是RDB(全量)和AOF(增量),4.0之后提供了RDB-AOF混合持久化方案,充分利用了AOF和RDB各自优势。本文将就这三种方案从使用到底层原理进行介绍。

1. RDB

  RDB是一种全量持久化方案,启用RDB后,redis会在程序满足用户配置的规则时,将内存中的数据全量写入文件系统,已达到持久化的目的。

1.1 RDB配置

  redis持久化一般通过配置文件来进行配置,默认情况下(redis5.0.8),redis将内存数据保存到dump.rdb的二进制文件中,并且当每900秒且1次写操作,或每300秒10次写操作,或每60秒10000次写操作均会触发RDB持久化。我可以通过修改配置文件来修改上述持久化规则。

#持久化存储文件
dbfilename dump.rdb
#每900秒且1次写操作
save 900 1
#每300秒10次写操作
save 300 10
#每60秒10000次写操作
save 60 10000

  同个配置文件中可以通过多条save命令来达到满足指定条件中任一规则时,触发持久化。即当存在多个save命令,他们为“或”的关系。若不想开启RDB持久化,只需要将所有的save保存策略注释掉即可。

1.2 手动生成RDB快照

  除了通过配置文件配置redis自动生成RDB快照之外,我们还可以通过客户端运行save或bgsave命令,来手动让redis生成RDB快照文件。每次命令执行后redis会将所有内存数据生成一个RDB格式文件,并覆盖原有的RDB快照文件。
  save是同步命令,bgsave是异步命令,bgsave会从redis主进程fork出一个子进程,专门用来生成RDB快照文件。save与bgsave对比如下:

命令 save bgsave
IO类型 同步 异步
是否阻塞redis其它命令
复杂度 O(n) O(n)
优点 不会消耗额外内存 不阻塞客户端命令
缺点 阻塞客户端命令 需要fork子进程

注意:通过1.1节配置文件来自动生成RDB文件的方式,redis使用的是bgsave的方式。

2. AOF

  AOF(append only file)类似于Mysql的binlog,是一种增量持久化方案。AOF方案下,redis会将用户操作的指令(只记录写命令)记录到AOF文件。

2.1 AOF配置

  默认情况下,redis不会开启AOF持久化方案,我们可以通过在配置文件中添加以下配置开启AOF:

#启用AOF持久化
appendonly yes
#配置AOF存储路径
appendfilename "appendonly.aof"

  AOF有三种规则可供选择,分别为always、everysec、no,用来设置redis将命令写入AOF文件的时机。

#有新命令立即追加到 AOF 文件,速度慢,但数据安全性最高
appendfsync always
#每秒同步一次命令到文件中,速度较快(和使用 RDB 持久化差不多),在故障发生时最多只会丢失 1 秒钟的数据
appendfsync everysec
#从不fsync,由操作系统自动调度刷磁盘,速度最快,但安全性最低。
appendfsync no

  推荐在对数据安全性要求不高的场景下,使用everysec的fsync策略,这种策略可以同时兼顾性能和安全性。

2.2 AOF原理

  如本节开头介绍,redis会在新的写命令被执行时记录该命令,并按照用户配置的策略将命令以RESP格式(redis客户端与服务端通信协议格式)写入文件系统。整个过程大致如下图所示:


redis AOF持久化过程
2.2.1 RESP

  RESP协议以 “*数字”标记为开头,表明指令共有多少段。每一段又以“$数字”标记开头,表明该段的内容长度,另外每个标记和内容均以过行符作为分隔。如下为执行“set everlin 1”命令的AOF文件内容:

*3
$3
set
$7
everlin
$1
1
2.2.1 AOF重写

  随着时间推移,AOF中记录的指令会越来越多,文件占用空间越来越大,当系统重启去加载AOF时,也会变得越慢。为了解决这一问题,redis提供了AOF重写的功能。AOF重写的理论依据是,我们会对某个key进行多次写操作,而我们很容易找到一个命令,对这个key执行后的结果,与前边多次操作的结果一致。
例如执行以下命令:

incr everlin
incr everlin
incr everlin

  在没有进行AOF重写时,AOF文件中的内容如下:

*2
$4
incr
$7
everlin
*2
$4
incr
$7
everlin
*2
$4
incr
$7
everlin

  在redis进行AOF重写后,AOF文件内容变为:

*3
$3
set
$7
everlin
$1
4

  需要注意,重写AOF文件的操作,redis并不是读取旧的AOF文件后进行成功学,而是将整个内存中的数据库内容用命令的方式重写了一个新的AOF文件,这点和快照有点类似。此外,在redis4.0之后,若开启了混合持久化方案,那么AOF重写的数据将不再以RESP格式写入,而是以RDB二进制格式写入AOF文件中。
AOF重写也需要配置策略才能触发,如下两个配置可以控制AOF自动重写频率

#AOF文件至少要达到64M才进行重写
auto-aof-rewrite-min-size 64mb
#AOF文件自上一次重写后文件大小增长了100%,再次触发重写
auto-aof-rewrite-percentage 100

  我们还可以通过在客户端使用bgrewriteaof命令,来对AOF进行手动重写。redis通过fork一个子进程进行AOF重写,因此,AOF重写不会对redis正常命令处理产生太大影响。

3. RDB VS AOF

  通过1、2节的介绍,我们整理出RDB与AOF持久化方案的对比如下:

特点 RDB AOF
文件体积
性能影响 由同步策略决定(参见2.1)
数据安全 容易丢数据 由同步策略决定(参见2.1)
恢复速度
3.1 同时开启RDB和AOF

  当同时开启RDB持久化和AOF持久化时,两种方案都会被redis启用。但当redis重启时,若同时存在RDB文件及AOF文件,redis会优先选择AOF文件进行数据恢复。因为AOF方案能保证数据更接近与上次redis停止时的数据。

4. 混合持久化方案

  前一节我们对比了RDB和AOF各自的优缺点,RDB占用存储空间小,恢复速度快,AOF数据安全性更高,那有没有方法可以发挥两者的优势,取长补短呢。答案是有的,redis4.0之后提供了混合持久化方案,该方案基本与AOF方案一致,不同点在于,当AOF重写时,以RDB格式对AOF进行重写。此时AOF的文件结构如下:


混合持久化方案下AOF文件结构

  混合持久化方案提供了一种简单粗暴的方式,取长补短,既保留了RDB文件体积小,恢复速度快的优势,又解决了RDB持久化容易丢失数据的问题。我们可以在配置文件中使用以下配置,启用混合持久化:

aof-use-rdb-preamble yes

5. 小结

  本文分别介绍了RDB,AOF,混合持久化3种持久化方案:RDB文件体积小,恢复速度快,但容易丢失数据;AOF可根据fsync策略提供不同的数据安全等级,可以做到数据不丢失,但其恢复速度慢,redis提供了AOF重写来压缩其文件体积,提高恢复速度;混合持久化结合了RDB和AOF的优势,在AOF重写时以RDB格式将数据置于AOF文件开头,大大提高了AOF的恢复速度,同时也保留了其数据安全性高的优势。建议在需要进行持久化的场景下,选用混合持久化方案。

你可能感兴趣的:(Redis:数据持久化)