redis数据持久化

持久化概念介绍

通常数据持久化简单可理解为存储在内存当中的数据二次存储至本地磁盘中,达到内存丢失的情况下数据依然有留存。而Redis则提供了两种持久化方案:RDB(Redis DataBase) 和 AOF(Append Only File)。

RDB方式

RDB方式是一种快照式的持久化方法,将某一时刻的数据持久化到磁盘中。

  • redis在进行数据持久化的过程中,会先将数据写入到一个临时文件中,待持久化过程都结束了,才会用这个临时文件替换上次持久化好的文件。正是这种特性,让我们可以随时来进行备份,因为快照文件总是完整可用的。
  • 对于RDB方式,redis会单独创建(fork)一个子进程来进行持久化,而主进程是不会进行任何IO操作的,这样就确保了redis极高的性能。
  • 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。

AOF方式

AOF方式是将执行过的写指令记录下来,在数据恢复时按照丛前到后的顺序再将指令执行一遍。

  • AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大.默认的AOF持久化策略是每秒钟fsync一次(fsync是指把缓存中的写指令记录到磁盘中),因为在这种情况下,redis仍然可以保持很好的处理性能,即使redis故障,也只会丢失最近1秒钟的数据。
  • 如果在追加日志时,恰好遇到磁盘空间满、inode满或断电等情况导致日志写入不完整,也没有关系,redis提供了redis-check-aof工具,可以用来进行日志修复。
  • 因为采用了追加方式,如果不做任何处理的话,AOF文件会变得越来越大,为此,redis提供了AOF文件重写(rewrite)机制,即当AOF文件的大小超过所设定的阈值时,redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。举个例子或许更形象,假如我们调用了100次INCR指令,在AOF文件中就要存储100条指令,但这明显是很低效的,完全可以把这100条指令合并成一条SET指令,这就是重写机制的原理。
  • 在进行AOF重写时,仍然是采用先写临时文件,全部完成后再替换的流程,所以断电、磁盘满等问题都不会影响AOF文件的可用性。

两种持久化方式对比

RDB AOF
备份 全量备份,一次保存整个数据库 增量备份,一次保存一个修改数据库的命令
保存间隔 较长 默认1秒
还原速度 一般
阻塞 save会阻塞,但bgsave或者自动不会阻塞 无论是平时还是AOF重写,都不会阻塞
场景 适合数据备份,默认开启 适合保存数据,和一般sql持久化方式一样,默认关闭
启动优先级
体积
恢复速度
安全性 易丢数据 根据策略决定
轻重

配置方式

RDB配置方式

默认情况下,是快照rdb的持久化方式,将内存中的数据以快照的方式写入二进制文件中,默认的文件名是dump.rdb
redis.conf 默认配置:

1
2
3
save 900 1     # 900秒之内,如果超过1个key被修改,则发起快照保存;
save 300 10 # 300秒内,如果超过10个key被修改,则发起快照保存;
save 60 10000 # 1分钟之内,如果1万个key被修改,则发起快照保存;

这种方式不能完全保证数据持久化,因为是定时保存,所以当redis服务down掉,就会丢失一部分数据,而且数据量大,写操作多的情况下,会引起大量的磁盘IO操作,会影响性能。

所以,如果这两种方式同时开启,如果对数据进行恢复,不应该用rdb持久化方式对数据库进行恢复。

AOF配置方式

使用aof做持久化,每一个写命令都通过write函数追加到appendonly.aof中。

配置方式:启动aof持久化的方式:

1
2
3
4
5
6
vim redis.conf

...
dir ./
appendonly yes # 默认是no,开启后,会在dir对应的目录中生成一个appendonly.aof
...

使用AOF做持久化,每一个命令以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。 Redis 还可以在后台对 AOF 文件进行重写,使得 AOF文件的体积不会超出保存数据集状态所需的实际大小。实际上,AOF持久化并不会立即将命令写入到硬盘文件中,而是写入到硬盘缓存,在接下来的策略中,配置多久来从硬盘缓存写入到硬盘文件。所以在一定程度一定条件下,还是会有数据丢失,不过你可以大大减少数据损失

1
2
3
# appendfsync always
appendfsync everysec
# appendfsync no

配置说明:

always: 每次操作都会立即写入aof文件中

everysec: 每秒持久化一次(默认配置)

no: 不主动进行同步操作,默认30s一次

可以看出,always效率最低。建议使用everysec,数据安全性高。Redis允许我们同时使用两种模式

数据持久化测试

RDB 模式

在redis.conf配置文件中修改配置(默认配置不方便测试,可将频率设置大一点),在redis.conf添加一条进行测试:

1
2
3
4
5
save 900 1
save 300 10
save 60 10000

save 5 1 # 测试使用

保存后,重启Redis服务,客户端连接测试(-a 连接Redis服务的密码,这里是redis;-p 端口号,默认可不设置):

1
# redis-cli -a redis -p 6381
1
2
3
4
5
6
7
8
127.0.0.1:6381> set name sdf
OK
127.0.0.1:6381> set age 12
OK
127.0.0.1:6381> set n 123
OK
127.0.0.1:6381> set m 23
OK

这时,发现dump.rdb文件的修改日期变了,并且redis服务端增加了保存日志:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@localhost ~]# tail -f redis-service.log 
1429:M 09 Apr 13:15:11.891 * 1 changes in 5 seconds. Saving...
1429:M 09 Apr 13:15:11.892 * Background saving started by pid 1604
1604:C 09 Apr 13:15:11.897 * DB saved on disk
1604:C 09 Apr 13:15:11.898 * RDB: 6 MB of memory used by copy-on-write
1429:M 09 Apr 13:15:11.993 * Background saving terminated with success
1429:M 09 Apr 13:15:17.477 * 1 changes in 5 seconds. Saving...
1429:M 09 Apr 13:15:17.478 * Background saving started by pid 1605
1605:C 09 Apr 13:15:17.481 * DB saved on disk
1605:C 09 Apr 13:15:17.482 * RDB: 6 MB of memory used by copy-on-write
1429:M 09 Apr 13:15:17.579 * Background saving terminated with success


1429:M 09 Apr 13:15:40.821 * 1 changes in 5 seconds. Saving...
1429:M 09 Apr 13:15:40.823 * Background saving started by pid 1630
1630:C 09 Apr 13:15:40.829 * DB saved on disk
1630:C 09 Apr 13:15:40.830 * RDB: 6 MB of memory used by copy-on-write
1429:M 09 Apr 13:15:40.923 * Background saving terminated with success

接下来,重启redis服务端和客户端,看数据是否真的持久化了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6381> keys *
1) "age"
2) "n"
3) "m"
4) "ns"
5) "name"
127.0.0.1:6381> get name
"sdf"
127.0.0.1:6381> get age
"12"
127.0.0.1:6381> get n
"123"
127.0.0.1:6381> get m
"23"

有数据,说明RDB快照持久化成功。

AOF 模式

redis.conf默认配置:

1
appendonly no

需要把配置文件的appendonly修改为yes,开启持久化。开启后,重启redis服务,会在配置文件”dir “(强烈建议:dir 要指定具体目录,如果使用默认的./目录的话,会根据你执行启动Redis服务的路径生成数据文件,这样即便做了持久化,在不同的路径下启动Redis服务会生成不同的路径,这样数据就很乱套了)开头的指定数据存放目录下生成一个appendonly.aof的文件,就是前文提到的内容。连接Redis服务进行操作验证,这里借着前文的数据进行验证,最后执行flushall清空数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6381> keys *
1) "age"
2) "n"
3) "m"
4) "ns"
5) "name"
127.0.0.1:6381> get m
"23"
127.0.0.1:6381> get ns
"112"
127.0.0.1:6381> flushall
OK
127.0.0.1:6381> keys *
(empty list or set)

打开appendonly.aof,可以看到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
set
$3
age
$2
12
*3
$3
set
$1
n
$3
123
*3
$3
set
$1
m
$2
23
*1
$8
flushall

把最后的flushall删除掉,重启Redis服务,连接再次查看:

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6381> keys *
1) "ns"
2) "m"
3) "name"
4) "n"
5) "age"
127.0.0.1:6381> get ns
"112"
127.0.0.1:6381> get m
"23"

有数据了,说明AOF持久化也成功了,至此,两种模式都已验证数据的持久化。