今天分享一下Redis的数据持久化方式,我们知道,Reids是一个高性能的缓存中间件,它的高性能是因为它是基于内存的,我们知道直接操纵内存是比较快的,不过一些美好的事物总会有牺牲一些功能,因为是基于内存,所以当机器发生宕机,那么数据就会完全丢失,Redis怎么可能不会去重视这个问题呢,所以它也提供了数据持久化的方式。
持久化方式
Redis提供了两种数据持久化的方式,分别为RDB和AOF,RDB是基于内存快照的,它会将某一时刻Redis的内存状态写入磁盘,RDB也是Redis默认采用的持久化方式,AOF则是基于文件追加的机制来进行持久化的,如果我们开启AOF持久化,那么每写入一条数据,这个写入数据的命令就会被追加到AOF文件的尾部,下面详细介绍这两种持久化方式。
RDB持久化
RDB是Redis默认的持久化方式,它是基于内存快照的持久化方式,何为快照?快照就是某一时刻Redis内存中的所有数据,就好比我们使用WPS编写文档,突然有事情需要处理,这时候我们要将电脑关闭,为了不让编辑的内容丢失,我们关闭WPS时它会提醒保存文档,这时候就会把到我们最后一刻操作之前的所有数据都保存下来,下次打开的时候 ,我们可以从上次编辑的地方继续。
RDB配置
我们关注以下三个配置就行
save 3600 1 300 100 10 10000
dbfilename dump.rdb
dir ./
save
配置达到什么条件才保存内存快照,这个配置表示如果在3600秒内进行一次写操作,或者在300秒内进行100次写操作,又在10秒内进行10000次写操作,那么就会保存内存快照。
dbfilename
表示生成的RDB二进制文件名,默认为dump.db
,dir ./
是生成的RDB二进制文件的存放路劲。
当上面的save中的条件触发,那么Redis就会保存内存快照,当然,我们也可以直接使用SAVE
和BGSAVE
命令来保存内存快照,save这里的配置到最后还是去执行SAVE
和BGSAVE
命令,下面介绍SAVE
和BGSAVE
命令。
SAVE和BGSAVE命令
在Redis命令行执行SAVE命令或者BGSAVE命令都可能保存快照,只不过SAVE命令会阻塞Redis服务器,这时候客户端发送的所有请求Redis都会拒绝,如果RDB文件比较小的还好,如果比较大,那么恢复数据就需要花费一定的时间,对于客户端来就很不友好,所以这时候我们可以使用BGSAVE命令,执行BGSAVE命令,Redis会fork一个子进程去保存内存快照,这样Redis服务器就不会阻塞。
下面我们对配置进行修改来测试rdb。
改成下面配置,那么10s内如果有1次写操作,就会保存当前快照。
save 3600 1 300 100 10 1
我们往Redis中添加一个key后,后台就会打印保存到磁盘的日志。
在Redis源码中,保存RDB文件在rdb.c文件中,使用rdbSaveBackgroup
函数保存RDB文件,里面会fork一个子进程,然后调用rdbSave
保存rdb文件。
恢复RDB文件
如果Redis服务发生宕机,那么在服务器恢复后,Redis会加载rdb文件进行恢复,Redis没有专门恢复rdb文件的命令,服务器在启动后会直接判断是否存在rdb文件,如果存在则进行恢复。
在redis中,在rdb.c文件中使用rdbLoad
函数进行加载rdb文件和恢复到Redis内存中。
AOF持久化
AOF (Append Only File)持久化机制会记录每一条写入 Redis 数据库的命令,将其追加到文件末尾中,以此来保证数据的持久化和安全性。AOF 持久化方式保证了Redis的每一次写的操作都可以被记录到文件中,增加了数据的可靠性和稳定性。这种方式下,每个写入命令都将同步到 AOF 文件中。AOF 优先于 RBD 进行持久化,如果 Redis 服务重启之前启用了 AOF 持久化方式,那么 Redis 会自动从 AOF 日志文件中重建数据。AOF 产生的日志文件是一个文本文件,易于查看,但也可能稍微耗时一些。
AOF配置
我们来关注AOF的几个配置
appendonly yes
appendfilename "appendonly.aof"
appenddirname "appendonlydir"
appendfsync everysec
appendonly
表示是否开启AOF持久化机制,默认为no,表示不开启,Redis默认不开启AOF持久化,所以如果我们需要开启AOF持久化,那么就需要将其设置为yes。
appendfilename
表示aof文件的名称,开启aof持久化,每个写操作的命令会被写入aof文件中,redis7以后,不单单生成了appendonly.aof文件,而是生成了三个文件,
appenddirname
表示aof所在文件夹的名称,默认为appendonlydir。
appendfsync
表示设置同步aof文件的时机,当我们设置了aof持久化机制,写入的命令并不会直接写入磁盘中的aof文件,而是保存在内存的一个缓冲区aof_buf中,然后再通过相应的机制刷盘到磁盘中,提供了 always,everysec,no 三种选项
- always:每当向缓冲区文件中添加数据时,立即执行同步操作将缓冲区的内容同步到aof文件中。这样可以保证数据的完整性,但会导致 Redis 性能下降。
- everysec:每秒将aof缓冲区中的数据同步到磁盘。这种方式既保证了数据的完整性,又可以大大提高 Redis 的性能。
- no:不执行同步操作,而是交由操作系统控制同步时机。这种方案性能最好,但也有可能会导致数据丢失。
测试AOF持久化机制
开启了AOF持久化机制后,我们往Redis中写入几条数据,然后查看aof文件。
往Redis中写入了一个名为 steakliu 的key,value为空,然后为steakliu这个key设置value为 steakliu is a handsome boy,这是两个命令,我们查看aof文件,发现里面有这两条命令,里面还有一个 SELECT 0
,它是Redis自动加入的。
在Redis中有一个时间循环机制,它会接受来自客户端的请求,然后进行处理,当然也包括将命令写入aof文件中,最终会调用flushAppendOnlyFile
函数。
上面代码中我们看到里面有一个aof_buf,它的类型是sds,在Redis中sds名为简单动态字符串(Simple Dynamic String)。
sds aof_buf; /* AOF buffer, written before entering the event loop */
上面的配置中我们说了appendfsync
,它的作用就是将aof_buf缓冲区中的数据同步到aof文件中。
通过AOF恢复数据
将Redis进程kill掉,然后重新启动Redis,我们看出它会去加载aof文件进行数据恢复。
因为aof文件中保存的是写操作的命令,所以在进行恢复的时候就是重新执行一下这些命令就能进行恢复。
AOF重写
随着aof文件的变大,如果我们的Redis服务出现故障后重启,它使用aof来恢复数据时,就会比较耗时,如果里面存在大量重复的命令,比如下面我们对steak-key进行反复的修改,但是实际上我们只需要最新的value,而里面出现了大量的重复,就会导致恢复时间比较慢。
为了解决这个问题,Redis提供了aof重写机制,它使用了BGREWEITEAOF命令来对aof文件进行重写,Redis会开启一个子进程来进行重写,它会编辑aof文件中命令,去除重复的,然后转换到一个新的aof文件中。
循环添加重复的key
如下,我们往redis中循环添加两个重复的key,分别是steak-key
和steak-pai
。
我们观察一下aof文件夹中的几个aof文件如下。
稍等一会儿,我们再看aof文件夹下面的这几个aof文件如下:
从上面我们可以看出,appendonly.aof.1.base.aof
变为了appendonly.aof.2.base.aof
,appendonly.aof.1.incr.aof
变为了appendonly.aof.2.incr.aof
,由此可见aof文件发生了重写。
我们查看appendonly.aof.2.base.aof
的内容如下:
我们发现这个文件夹中只有两个key,也就是steak-key
和steak-pai
,如果不进行重写,那么就会存在大量重复的key,在进行恢复的时候就比较慢。
注:上面我们并没有开启RDB和AOF混合使用,所以我们能看到明文,如果开启了RDB和AOF混合使用,文件中则有RDB二进制数据和AOF内容,我使用的是Redis7版本,默认是开启RDB和AOF混合使用,可以在redis.conf中进行配置。
aof-use-rdb-preamble yes
yes表示开启RDB和AOF混合使用,no表示关闭,Redis7默认的是开启。
redis.conf配置
redis中有两个aof重写的配置。
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
- auto-aof-rewrite-percentage 表示当 AOF 文件大小增长到上一次重写文件时的大小的百分之多少时,Redis 就会自动触发 AOF 重写。例如,当此配置项为 100 时,表示当 AOF 文件大小增长到上次重写时大小的两倍时,就会自动触发 AOF 重写。
- auto-aof-rewrite-min-size 表示 Redis 在自动触发 AOF 重写时设置的 AOF 文件最小大小限制。例如,当此配置项为 64MB 时,如果 AOF 文件大小增长到达了触发自动重写的条件,但当前 AOF 文件大小还不到 64MB,则不会自动触发 AOF 重写。
从上面我们可以看出,aof如果不进行重写,那么如果出现大量的重复key,aof文件中就会保存了大量重复的命令,在进行aof恢复的时候,会做很多无用功
。
AOF和RDB优缺点比较
RDB的优点
RDB是一种快速而有效的备份方式,可以在特定的时间间隔内保存Redis数据的快照,储存快照文件的方式是写入硬盘中的二进制文件,所以很适合用来备份关键数据,RDB备份是二进制格式,所以比较小,使用起来比较节省存储空间。RDB还支持压缩备份,可以在备份数据时压缩文件大小,节省备份成本。
RDB的缺点
RDB在执行快照的时候,如果数据量较大,会造成Redis阻塞,如果服务器宕机,比如发生异常关机,那么这部分数据就可能发生丢失,因为RDB是定期进行备份,如果Redis服务器发生故障,那么会丢失上次备份到现在的数据。
AOF的优点
AOF是一种以日志的形式来记录Redis服务器所执行的所有写入操作,具有很好的复原能力,因此更适合于重要数据的保存,AOF支持在重写,以保证AOF文件不会无限增大导致读取缓慢。
AOF的缺点 AOF文件通常比RDB文件大,如果日志分析不当,则可能增加服务器I/O的负载,AOF方式的数据恢复速度通常比RDB方式的恢复速度慢,因为它还需要去一个一个地执行命令进行恢复。
AOF和RDB混合使用
AOF和RDB可以混合使用,上面我们也提到了RDB和AOF混合使用可通过aof-use-rdb-preamble配置,Redis7默认是开启混合持久化的,那么就会将RDB二进制内容和AOF增量内容保存在一起。
参考文档和书籍
Redis设计与实现[https://weread.qq.com/web/bookDetail/d35323e0597db0d35bd957b]
Redis官方文档[https://redis.io/docs/management/persistence/]