Redis数据持久化
Redis可不单单是一个缓存型数据库,如果出现Redis服务出现问题导致关闭或者人为的操作导致停止运行,那么所有的数据都将丢失。
为此Redis推出了数据持久化的方案,Redis推出了两种方案:RDB与AOF
RDB快照
什么是RDB快照,RDB快照有点类似于传统数据库的db文件。指的是将Redis中的数据以二进制格式存储在RDB文件中,因为是在磁盘上进行的操作,所以每次写入数据都是IO操作。为了减少磁盘的负担,Redis支持修改RDB文件的写入时间间隔:
save <seconds> <changes>
表示在seconds秒内,至少有changes次变化,就会自动触发bgsave
命令
save 900 1
当时间到900秒时,如果至少有1个key发生变化,就会自动触发bgsave
命令创建快照save 300 10
当时间到300秒时,如果至少有10个key发生变化,就会自动触发bgsave
命令创建快照save 60 10000
当时间到60秒时,如果至少有10000个key发生变化,就会自动触发bgsave
命令创建快照
快照最大的优点就是你可以将rdb文件进行备份,可以存放到其他服务器作为备用。
触发快照的时机
- 执行
save
和bgsave
命令 - 配置文件设置
save <seconds> <changes>
规则,自动间隔性执行bgsave
命令 - 主从复制时,从库全量复制同步主库数据,主库会执行
bgsave
- 执行
flushall
命令清空服务器数据 - 执行
shutdown
命令关闭Redis时,会执行save
命令
save与bgsave的区别
save会阻塞Redis服务器进程
bgsave则不同,它会fork一个子进程,然后在子进程中创建rdb文件,不会阻塞Redis服务器进程
bgsave流程图:
AOF持久化
AOF不同于RDB,AOF是以日志形式记录每次数据的变化。当数据产生变化后,首先Redis会记录这条命令,将命令以命令追加的形式存储在aof_buf
内存缓冲区,这也是为了避免多次的IO影响性能。
可以通过修改配置文件redis.conf
来开启这个功能:
# appendonly参数开启AOF持久化
appendonly no
# AOF持久化的文件名,默认是appendonly.aof
appendfilename "appendonly.aof"
# AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的
dir ./
# 同步策略
# appendfsync always
appendfsync everysec
# appendfsync no
# aof重写期间是否同步
no-appendfsync-on-rewrite no
# 重写触发配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 加载aof出错如何处理
aof-load-truncated yes
# 文件重写策略
aof-rewrite-incremental-fsync yes
文件写入(write)和文件同步(sync)
那么在aof_buf
缓冲区的命令何时存储到AOF文件中呢?Redis提供了下面几个策略
appendfsync always
:将aof_buf
缓冲区的所有内容写入并同步到AOF文件,每个写命令同步写入磁盘appendfsync everysec
:将aof_buf
缓存区的内容写入AOF文件,每秒同步一次,该操作由一个线程专门负责appendfsync no
:将aof_buf
缓存区的内容写入AOF文件,什么时候同步由操作系统来决定
appendfsync
选项的默认配置为everysec
,即每秒执行一次同步
关于AOF的同步策略是涉及到操作系统的write
函数和fsync
函数的,在《Redis设计与实现》中是这样说明的
为了提高文件写入效率,在现代操作系统中,当用户调用
write
函数,将一些数据写入文件时,操作系统通常会将数据暂存到一个内存缓冲区里,当缓冲区的空间被填满或超过了指定时限后,才真正将缓冲区的数据写入到磁盘里。这样的操作虽然提高了效率,但也为数据写入带来了安全问题:如果计算机停机,内存缓冲区中的数据会丢失。为此,系统提供了
fsync
、fdatasync
同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保写入数据的安全性。
AOF重写
AOF也有一个很明显的缺点,随着时间的推移,Redis无休止的对AOF文件进行命令追加,必然会把AOF文件填充的十分庞大。那么如何优化这个问题?
AOF支持文件重写bgrewriteaof
,它会像bgsave
一样先fork
一个子进程,在子进程中执行文件重写。
bgrewriteaod
有两触发方式:
- 手动触发
bfrewriteaof
- 自动触发
自动触发我们可以在redis.conf
设置触发条件:
# 表示当AOF文件的体积大于64MB,且AOF文件的体积比上一次重写后的体积大了一倍(100%)时,会执行`bgrewriteaof`命令
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
-
重写会有大量的写入操作,所以服务器进程会
fork
一个子进程来创建一个新的AOF文件 -
在重写期间,服务器进程继续处理命令请求,如果有写入的命令,追加到
aof_buf
的同时,还会追加到aof_rewrite_buf
AOF重写缓冲区 -
当子进程完成重写之后,会给父进程一个信号,然后父进程会把AOF重写缓冲区的内容写进新的AOF临时文件中,再对新的AOF文件改名完成替换,这样可以保证新的AOF文件与当前数据库数据的一致性
RDB VS AOF
RDB优点
- 快照是以二进制压缩文件存储的,存储空间小,易于备份,如果可能出现大量数据丢失的情况推荐用这个方案
- 子进程运行,不影响Redis其他服务
- 恢复大量数据比AOF快的多
RDB缺点
- 安全性没有AOF高,如果出现服务器宕机会丢失一段时间内的数据
AOF优点
- 安全性高,秒级数据存储,出现意外最多丢失一秒的数据
AOF缺点
-
AOF是以Redis序列化协议存储的,同数据集体积下,RDB文件大小比AOF小很多
-
由于AOF文件庞大, 数据恢复也会比RDB慢
总结
RDB与AOF各有优势,如何选择得看业务场景。如果一秒的数据都不能丢,那么需要开启AOF。如果对于性能要求比较高并且能够承受几分钟的数据丢失,那么建议开启RDB。当然也有两种持久化方案都开启的情况。