简介
Redis作为目前最常用的K-V缓存数据库,因其具有访问速度快而备受欢迎,而其极快的访问速度是基于数据都在内存中来达到的。但是我们并不能保证服务永远是100%可用的,能保证99.999%可用就已经很了不得了,如果数据仅仅存储于内存中,那么意外的宕机就会导致数据丢失,那么对一些数据敏感的业务势必会造成不可泯灭的影响。所以Redis提供了数据持久化功能,目的就是将内存中的数据保存到磁盘上,同时也要最大可能的不影响读写操作的性能。
Redis提供了RDB(redis Database)和AOF(Append Only File)两种持久化方式,默认开启了RDB方式,该模式会在Redis启动后,自动生成dump.rdb文件,默认在redis-server命令的目录下。
下面我们详细的介绍一下这两种持久化方式。
RDB(redis Database)
在仅开启RDB模式的情况下,Redis启动时,会先加载dump.rdb文件,将磁盘快照加载到Redis内存中,默认会在redis-server所在目录下查找dump.rbd文件,而当我们再启动时指定了redis.conf文件,那么则使用redis.conf文件中配置的dir
选项指定的dump.rdb文件路径。
RDB模式是将Redis内存中存储的数据全部以二进制的方式存储到磁盘上,就像是word文档的定时自动保存功能,防止数据丢失。
触发RDB持久化的方式很简单,大致有三种:
-
客户端发送save命令
当客户端向服务器发送save命令时,服务器会阻塞save命令只会的其他请求,直到数据同步完成。如果Redis内存中数据量太大,同步数据操作执行时间过长,而这期间Redis服务器会阻塞其他所有请求,所以,此命令和
keys *
命令一样,不能在生产环境使用。 -
客户端发送bgsave命令
bgsave命令和save命令功能一样,都是触发执行RDB持久化,不同的是当客户端发出bgsave命令时,Redis服务端会fork一个子进程来执行数据持久化,当内存中的数据全部持久化完成之后,子进程会自动退出。所以基于这种方式,主进程仍然可用继续接收其他请求,但是fork子进程的过程是同步的,也就是说在fork子进程的过程中,Redis服务器同样不能接收其他请求,所以如果fork子进程的过程耗费太长时间,仍然有阻塞其他客户端请求的情况发生。
-
服务端自动触发
Redis在redis.conf配置文件中通过save参数指定触发RDB持久化的条件,该方式和bgsave一样,会fork一个子进程执行RDB持久化,但是如果设置的触发时间太短,则容易频繁的写入rdb文件,频率过高的话会严重影响服务器性能,但是时间设置太长则会有造成数据丢失的可能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25################################ SNAPSHOTTING ################################
#
# Save the DB on disk:
#
# save <seconds> <changes>
#
# Will save the DB if both the given number of seconds and the given
# number of write operations against the DB occurred.
#
# In the example below the behaviour will be to save:
# after 900 sec (15 min) if at least 1 key changed
# after 300 sec (5 min) if at least 10 keys changed
# after 60 sec if at least 10000 keys changed
#
# Note: you can disable saving completely by commenting out all "save" lines.
#
# 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 10000save 900 1
:900s内如果有至少1条写命令,则触发RDB持久化save 300 10
:300s内如果有至少10条写命令,则触发RDB持久化save 60 10000
:60s内如果有至少10000条写命令,则触发RDB持久化save ""
:关闭RDB持久化
AOF(Append Only File)
AOF方式在Redis中是默认未开启的,在开启AOF后,会将内容写入到appendonly.aof文件中,文件的内容是服务器接收到的所有对数据进行修改的命令集合,按照时间顺序追加到文件尾部,并且在故障恢复的时候,会优先读取appendonly.aof文件中的内容,因为aof的默认策略是每秒钟写入一次,所以当采用aof进行持久化的时候,最多也仅仅丢失一秒的数据。
配置信息:redis.conf文件中
随着服务运行时间越来越久,内存中的数据变更次数越来越多,会造成aof文件越来越大,当然我们可以在配置文件redis.conf中设置aof文件重写策略,默认当aof文件大小达到64mb且增长比例超过了之前是100%的时候进行重写,重写的规则是将内存中的数据的当前值全部以对应的set命令写入到新的aof文件中,比如当前aof文件100mb,重写之后80mb,那么只有当文件再次达到160mb(160>=80*2&&160>64)的时候才会再次进行重写。如果在AOF文件写入的过程中突然宕机,可能会导致aof文件损坏,我们可以使用redis-check-aof --fix命令来修复。
1 | ###### APPEND ONLY MODE ###### |
🌰
我们开启AOF之后,向Redis中set三个key:
1 | set cc 1 |
然后查看AOF文件信息,发现文件大小有109个字节:
那我们顺便也看一下RDB文件的大小,执行save
命令生成dump.rdb文件,文件显示有117字节,比AOF要大一些:
然后分别查看appendonly.aof和dump.rdb的内容:
aof
1 | *2 |
rdb
1 | 5245 4449 5330 3030 39fa 0972 6564 6973 |
我们可以看到,从aof文件中,我们是可以推算出当前Redis数据库中的数据,具有很强的可读性,而rdb文件中则是完全看不懂的东西,并且aof只记录了set命令,我们执行的keys *
并没有记录到文件中,所以aof仅仅会将对数据产生影响的命令记录下来,其他指令都会被忽略。
AOF重写
AOF是采用文件追加的方式做持久化,这就无法避免文件会越来越大,所以Redis针对于这种情况,提供了aof文件rewrite机制,当aof文件超过redis.conf中配置的情况时,就会自动触发rewrite操作,只保留同一个key的最近的一条指令记录,且默认在rewrite的时候暂停aof持久化,我们也可以使用指令bgrewriteaof
手动的触发aof的rewrite。
1 | # 在aof文件rewrite的时候不做持久化 |
🌰
我们看一下rewrite的效果,我们在上面操作的基础上,重新给cc1设置一个新值set cc1 5
,然后看一下aof文件的变化:
-
rewrite前
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21*3 # 1 start
3
set
3
cc1
1
2 # 1 end
*3
3
set
3
cc2
1
3
*3 # 2 start
3
set
3
cc1
1
5 # 2 end -
rewrite后
1
2
3
4
5
6
7
8
95245 4449 5330 3030 39fa 0972 6564 6973
2d76 6572 0535 2e30 2e35 fa0a 7265 6469
732d 6269 7473 c040 fa05 6374 696d 65c2
bde4 e25e fa08 7573 6564 2d6d 656d c220
2710 00fa 0c61 6f66 2d70 7265 616d 626c
65c0 01fe 00fb 0700 0001 77c0 0100 0263
63c0 0100 0179 c006 0001 72c0 0300 0363
6333 c004 0003 6363 31c0 0500 0363 6332
c003 ff53 cd65 6417 1561 88为什么rewrite之后,aof文件的内容和rdb文件的格式一样了(此处仅仅是格式一样,内容并不一样)?好像和上面说的不一样啊,说好的指令压缩呢?
其实这都是redis.conf配置文件的默认配置作祟,我们还是来看下配置文件里面再AOF这块的最后一个配置参数:
1
2
3
4
5
6
7
8
9
10# When rewriting the AOF file, Redis is able to use an RDB preamble in the
# AOF file for faster rewrites and recoveries. When this option is turned
# on the rewritten AOF file is composed of two different stanzas:
#
# [RDB file][AOF tail]
#
# When loading Redis recognizes that the AOF file starts with the "REDIS"
# string and loads the prefixed RDB file, and continues loading the AOF
# tail.
yes可以谷歌翻译一下,大致意思是AOF在重写的时候,会使用优先RDB文件进行快速rewrite。那么如果我们想要AOF仍然保持指令级的重写,只需要将参数
aof-use-rdb-preamble
修改为no
即可,也就是aof-use-rdb-preamble no
,修改之后再执行一次bgwriteaof
,aof文件就正常了,如果还不正常,就把aof文件删了之后再执行。1
2
3
4
5
6
7
8
9
10
11
12
13
14*3
3
set
3
cc2
1
3
*3 # 2 start
3
set
3
cc1
1
5 # 2 endaof-use-rdb-preamble
在5.0版本之后是默认开启的,在4.0版本是默认关闭的,主要流程是Redis会先fork出一个子进程,将内存副本全量的以rdb的方式写入到aof文件,然后再将重写缓冲区的增量命令追加到文件中,写入完成后通知主进程进行文件替换,也就是会出现aof文件前半段是rdb格式,后半段是aof格式,这样的优点是速度快,数据丢失少,而缺点就是可读性差,低版本无法识别aof文件内容。
优缺点
优点
- RDB
- 恢复备份速度快
- 最新全量数据备份,文件体积小,占用磁盘空间少
- 备份过程由子进程进行,对Redis主进程影响较小
- AOF
- 备份频繁,数据丢失的概率低
- 文件内容可读性较高
缺点
- RDB
- 备份频率低,数据丢失的概率较高
- 使用不当会引起Redis主进程阻塞
- 数据量过大的情况下,fork子进程的过程也会发生阻塞
- 子进程在执行过程中会耗费过多内存
- AOF
- 文件体积较大,占用磁盘空间多
- 恢复备份速度慢
- 文件易损坏
方式 | AOF | RDB |
---|---|---|
启动优化级 | 高 | 低 |
体积 | 大 | 小 |
恢复速度 | 慢 | 快 |
数据丢失概率 | 小(具体由策略决定) | 大 |
轻重 | 轻 | 重 |
在实际生产环境中,我们一般将两种方式全部打开,这样做的好处是可以用AOF将数据丢失概率降低,用RDB提升数据恢复速度,但是这样的话当两种持久化同时执行的时候,会严重影响服务器性能,所以择优使用吧。
如果两种方式都开启,Redis会优先使用AOF日志来恢复数据,比较AOF保存的文件比RDB更完整。