bboyjing's blog

Redis学习笔记七【Redis持久化】

本章节我们来看看Redis时如何就爱那个数据存储到硬盘里面,是的数据在Redis重启之后仍然存在的。Redis提供了两种不同的持久化方法来将数据存储到硬盘里面。一种方法叫快照(snapshotting),它可以将存在于某一时刻的所有数据都写入硬盘里;另一种方法教只追加文件(append-only file, AOF),它会在执行的写命令复制到硬盘里。这两种方法可以自由搭配使用,具体如何选择,需要根据用书的数据以及应用来决定。下面在Redis安装目录的redis.conf文件中查看下Redis默认的持久化配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//SNAPSHOTTING
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir ./
//APPEND ONLY MODE
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes

可以看出默认开启的时快照模式,AOF模式是关闭的,具体的配置项是什么意思后面再看,这里先了解下哪里可以修改配置以及Redis默认行为。

快照持久化

用户可以将快照复制到其他服务器已达到备份的效果,也可以就将快照留在原地以便重启服务器时使用,快照文件存在dbfilename选项指定的文件中,并存储在dir指定的路径,根据默认配置即./dump.rdb,如果在新的快照文件创建之前,Redis、操作系统或者硬件三者任意一个崩溃了,Redis会丢失最近一次创建快照之后写入的所有数据。创建快照有以下几种方式:

  • 客户端主动发送BGSAVE命令来创建一个快照,BGSAVE命令返回Background saving started,Redis是通过调用fork来创建子进程完成快照写入硬盘的,父进程可以继续响应命令请求。
  • 客户端主动发送SAVE命令来创建一个快照,接到SAVE命令的Redis服务器在快照创建完毕之前将不再响应任何其他请求,此命令不常用。
  • 配置save选项,例如save 60 10000,那么从Redis最近一次创建快照之后开始算起,当”60秒之内有10000次写入”这个条件被满足时,Redis就会自动出发BGSAVE命令,如果设置了多个save配置选项,当任意一个满足时,Redis就会出发BGSAVE。默认行为配置了三个阙值。
  • 当Redis通过SHUTDOWN命令接受到关闭服务器的请求时,或者接受到标准TERM信号时,会执行一个SAVE命令,阻塞所有客户端,并在SAVE命令执行完毕之后关闭服务器。
  • 当一个Redis服务器连接另一个Redis服务器,并向对方发送SYNC命令开始一次复制操作的时候,如果主服务器没有或者并非刚刚执行BGSAVE操作,那么主服务器就会执行BGSAVE命令。

由于快照持久化会会在系统发生崩溃时丢失数据,因此只适用于那些即使丢失一部分数据叶不会造成问题的应用程序,如果不能接受这样的损失,可以参考后面AOF持久化。下面列举一些使用于快照持久化的场景:

1. 个人开发

个人开发服务器上,考虑到降低快照持久化带来的资源消耗,可以只设置sava 900 1,意思是距离上一次成功生成快照已经超过900秒,并且在此期间至少执行了一次写入操作,Redis就会自动开始一次新的BGSAVE操作。

2. 对日志进行聚合计算

在处理日志的同时,记录被处理日志的文件以及偏移量,如果Redis奔溃了而未能生成新的快照,可以从最后一次生成快照开始重新处理日志文件即可。

3. 大数据

当Redis存储数据量只有几个GB的时候,使用快照来保存数据是没有问题的,生成快照的时间叶非常短。但随着Redis占用的内存越来越多时,BGSAVE在创建子进程时耗费的时间也越来越多,所以选择合适的创建快照方式以及妥善地处理可能出现的数据丢失,对快照持久化数据来说相当重要。

AOF持久化

简单来说,AOF持久化会将被执行的写命令写到AOF文件的末尾,以此来记录数据的变化。因此,Redis只要从头到位重新执行一次AOF文件包含的所有命令,就可以恢复AOF文件所记录的数据集。下面列举appendfsync配置选项对AOF文件的同步频率的影响:

命令 描述
always 每个Reids写命令都要同步写入硬盘,这样做会严重降低Redis的速度
everysec 每秒执行一次同步,显示地将多个写命令同步到硬盘
no 让操作系统来决定应该何时进行同步

注:这里稍微解释下文件同步,在向硬盘写入文件时,写入内容首先会被存储到缓冲区,然后由操作系统决定何时将缓冲区内容写入到硬盘,这样才算真正的写入数据了。sync操作就是命令操作系统将文件同步到硬盘,同步操作会一直阻塞直到指定的文件被写入硬盘为止。当同步操作执行完毕之后,即使系统出现故障,只要硬盘不坏,就不会对被同步的文件造成任何影响。

appendfsync always选项是最安全同时也是最慢的,某些情况下还可能会影响固态硬盘的使用寿命,所以慎用!为了兼顾数据安全和写入性能,可以考虑使用appendfsync everysec,也是Redis默认行为。Redis每秒同步一次AOF文件的性能和不适用任何持久化特性时的性能相差无几,而每秒一次的同步,当系统出现故障时,也最多只会丢失一秒内产生的数据。appendfsync no选项是将写入硬盘的决定权交给操作系统,如果硬盘的写入速度不够快,缓冲区被填满时,Redis的写入操作将被阻塞,从而导致Redis处理命令请求的速度变慢,所以appendfsync no也不推荐使用。

重写/压缩AOF文件

AOF持久化看似很美好,有什么理由不使用呢?实际上并没那么简单,因为Redis会不断地将被执行的写命令记录到AOF文件中,AOF文件的体积会越来越大,极端情况下可能会撑满硬盘;另外一个问题是,Redis在重启之后需要通过重新执行AOF文件记录的所有写命令来还原数据集,所以如果AOF文件的体积非常大,那么还原操作执行的时间就可能非常长。
为了解决上述问题,可以向Redis发送BGREWRITEAOF命令,BGREWRITEAOF命令会通过移除AOF文件中的冗余命令来重写AOF文件,使得AOF文件的体积变得尽可能的小。也可以设置auto-aof-rewrite-percentage和auto-aof-rewrite-min-size来自动触发BGREWRITEAOF命令。Redis默认行为的意思是当AOF的体积大于64M,并且比上一次重写之后的体积大了至少一倍(100%)的时候,Redis将执行BGREWRITEAOF命令。如果AOF重写执行的国语频繁的话,可以调整auto-aof-rewrite-percentage选项的值设置为100以上,让Redis在AOF文件的体积变得更大之后才执行重写操作。