Redis的两种持久化机制(RDB和AOF)
什么是持久化
Redis的数据是存储在内存中的,内存中的数据随着服务器的重启或者宕机便会不复存在,在生产环境,服务器宕机更是屡见不鲜,所以,我们希望Redis能够将数据从内存中以某种形式保存到磁盘中,使得重启的时候可以加载磁盘中的文件记录恢复数据,这一过程便是Redis的持久化。
Redis支持两种持久化机制,一种是RDB,另一种是AOF。Redis默认情况下使用RDB方式进行持久化。两种持久化可以单独使用其中的一种,也可以二者结合使用,下面便来分别介绍下这两种持久化机制。
RDB方式
RDB方式的持久化是通过快照(snapshotting)方式完成的,当符合一定条件的时候redis会自动将内存中的数据生成一份副本存储在磁盘中,这个过程即为“快照”。
Redis会根据以下几种情况对数据进行快照:
- 根据配置规则自动进行快照
- 用户执行SAVE或者BGSAVE命令;
- 执行FLUSHALL命令;
- 执行复制时;
1)根据规则自定义快照条件
用户可以自定义快照条件,当符合快照条件,Redis便会执行快照操作,在redis.conf配置文件中,有这么一段配置及说明:
It is also possible to remove all the previously configured save
# points by adding a save directive with a single empty string argument
# like in the following example:
#
# save ""
save 900 1
save 300 10
save 60 10000
# By default Redis will stop accepting writes if RDB snapshots are enabled
# (at least one save point) and the latest background save failed.
# This will make the user aware (in a hard way) that data is not persisting
# on disk properly, otherwise chances are that no one will notice and some
# disaster will happen.
在save命令后面加上两个数字,save 。例如:save 900 1 表示在900秒内有一个或者一个以上的键被更改时即执行快照操作。
2)执行SAVE或者BGSAVE命令
1、save命令
执行save命令时redis会同步执行快照操作,这将会阻塞所有来自客户端的请求,服务器无法响应其他的处理,直到执行完成为止。如果数据量小,用此命令可能感觉不出有什么区别,但是当数据量很大的时候,就需要谨慎使用这个命令。
2、bgasve命令
执行bgsave命令时,redis会fork出一个子进程去完成备份的操作,不会影响redis处理其他的请求。
3)执行FLUSHALL命令
执行FLUSHALL命令时,Redis会清除数据库中的所有数据,不论清空数据库的过程是否触发了自动快照条件,只要快照条件存在,就会执行快照操作,当没有快照条件时,执行FLUSHALL不会进行快照。
4)执行复制时
当设置了主从模式时,Redis会在复制初始化时进行自动快照,即使没有设置自动快照条件时,也会执行快照操作。
存储路径:
Redis默认将快照文件保存在Redis当前进程的工作目录中的dump.rdb文件中,可以通过配置dir和dbfilename两个参数分别制定快照文案件的存储路径和文件名。如redis.conf文件中的配置和注释:
# The filename where to dump the DB
dbfilename dump.rdb
# The working directory.
# DB将以dbfilename指定文件名被写入这个目录中,
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
# Note that you must specify a directory here, not a file name.
dir ./
执行快照的过程
- Redis使用fork函数复制一份当前进程(父进程)的副本(子进程);
- 父进程继续接受来自客户端的请求,子进程开始将内存中的数据写入到硬盘中的临时文件;
- 当子进程写入完之后会用该临时文件替换旧的rdb文件。
redis在执行快照的过程中不会修改RDB文件,在快照结束后才会进行替换。因此RDB文件通常也用来实现Redis的数据备份,并且RDB文件是经过压缩的二进制格式,所以占用空间比内存中的数据小。
Redis启动后会读取RDB文件,将数据从磁盘加载到内存,通常将一个记录了1000万字符串类型键、大小为1GB的快照文件载入内存需要20~30秒,载入的时间根据不同的服务器性能和Redis的数据结构而不同。
RDB 的优缺点
优点:
1 适合大规模的数据恢复。
2 如果业务对数据完整性和一致性要求不高,RDB是很好的选择。
缺点:
1 数据的完整性和一致性不高,因为RDB可能在最后一次备份时宕机了。
2 备份时占用内存,因为Redis 在备份时会独立创建一个子进程,将数据写入到一个临时文件(此时内存中的数据是原来的两倍哦),最后再将临时文件替换之前的备份文件。
AOF方式
为了降低因为进程终止导致的数据丢失的风险,Redis还提供了AOF的方式来进行持久化,AOF可以将Redis执行的每一条命令追加到硬盘文件中,这一过程会降低redis的性能,但从数据的安全性来说,这个影响是可以接受的。
AOF文件的保存地址和RDB文件位置相同,都是通过dir参数设置,默认文件名为appendonly.aof。
如下所示:
appendonly no
# The name of the append only file (default: "appendonly.aof")
appendfilename "appendonly.aof"
默认情况下,Redis没有开启AOF的方式,可通过修改redis.conf配置文件中的appendonly参数为yes进行启动。
如果还没有生成aof文件的话,可以使用命令设置:
./redis-cli config set appendonly yes
aof文件打开是这样的:
*2
$6
SELECT
$1
0
*3
$3
SET
$3
age
$2
28
*3
$3
SET
$2
cc
$2
vv
AOF文件以纯文本的形式记录了Redis的执行命令,AOF文件中的内容是Redis客户端向Redis发送的原始通信协议的内容,当对相同key进行多次赋值操作时,aof也会将这些命令记录下来,但其实我们只希望它记录最后一次的值,为此Redis在redis.conf文件中提供了这样的参数来自动重写AOF文件:
# 当目前的AOF文件大小超过上一次重写的AOF文件大小的百分之多少进行重写
auto-aof-rewrite-percentage 100
# 允许重写的AOF的最小AOF文件大小
auto-aof-rewrite-min-size 64mb
Redis在启动的时候会逐条执行AOF文件中的命令来将硬盘中的文件写入到内存中,因此载入的速度相对慢些。
# The fsync() call tells the Operating System to actually write data on disk
# instead of waiting for more data in the output buffer. Some OS will really flush
# data on disk, some other OS will just try to do it ASAP.
#
# Redis supports three different modes:
#
# no: don't fsync, just let the OS flush the data when it wants. Faster.
# always: fsync after every write to the append only log. Slow, Safest.
# everysec: fsync only one time every second. Compromise.
# The default is "everysec", as that's usually the right compromise between
# speed and data safety. It's up to you to understand if you can relax this to
# "no" that will let the operating system flush the output buffer when
# it wants, for better performances (but if you can live with the idea of
# some data loss consider the default persistence mode that's snapshotting),
# or on the contrary, use "always" that's very slow but a bit safer than
# everysec.
#
# More details please check the following article:
# http://antirez.com/post/redis-persistence-demystified.html
#
# If unsure, use "everysec".
# appendfsync always
appendfsync everysec
# appendfsync no
并且我们需要注意的是下面这段描述:
The fsync() call tells the Operating System to actually write data on disk
# instead of waiting for more data in the output buffer. Some OS will really flush
# data on disk, some other OS will just try to do it ASAP.
虽然每次更改数据库内容的操作时,redis都会把更新记录在AOF文件中,但是由于操作系统的缓存机制,数据并没有真正的写入磁盘,而是进入了系统硬盘缓存。在默认情况下会每30秒执行一次同步操作,如果在这30秒之内系统异常会导致硬盘缓存中的数据丢失,我们使用AOF命令的方式就是为了尽可能的减少数据的丢失,所以redis提供了appendfsync参数来设置同步机制。默认情况下使用everysec,即每秒执行一次同步操作,将数据从缓存更新到磁盘中。always表示每次执行写入都会执行同步操作,这是最慢也是最安全的方式。no表示不主动执行,交由操作系统执行,这是最不安全的方式。一般情况下兼顾系统性能,使用everysec的方式即可。
优点:数据的完整性和一致性更高
缺点:因为AOF记录的内容多,文件会越来越大,数据恢复也会越来越慢。
RDB和AOF可以同时存在,这样既保证了数据安全又使得进行备份操作十分容易,Redis会使用AOF文件来恢复数据,因为AOF的方式持久化丢失的数据会更少。