Redis数据持久化

Redis可不单单是一个缓存型数据库,如果出现Redis服务出现问题导致关闭或者人为的操作导致停止运行,那么所有的数据都将丢失。

为此Redis推出了数据持久化的方案,Redis推出了两种方案:RDBAOF

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文件进行备份,可以存放到其他服务器作为备用。

触发快照的时机

  • 执行savebgsave命令
  • 配置文件设置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函数,将一些数据写入文件时,操作系统通常会将数据暂存到一个内存缓冲区里,当缓冲区的空间被填满或超过了指定时限后,才真正将缓冲区的数据写入到磁盘里。

这样的操作虽然提高了效率,但也为数据写入带来了安全问题:如果计算机停机,内存缓冲区中的数据会丢失。为此,系统提供了fsyncfdatasync同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保写入数据的安全性。

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_bufAOF重写缓冲区

  • 当子进程完成重写之后,会给父进程一个信号,然后父进程会把AOF重写缓冲区的内容写进新的AOF临时文件中,再对新的AOF文件改名完成替换,这样可以保证新的AOF文件与当前数据库数据的一致性

RDB VS AOF

RDB优点

  • 快照是以二进制压缩文件存储的,存储空间小,易于备份,如果可能出现大量数据丢失的情况推荐用这个方案
  • 子进程运行,不影响Redis其他服务
  • 恢复大量数据比AOF快的多

RDB缺点

  • 安全性没有AOF高,如果出现服务器宕机会丢失一段时间内的数据

AOF优点

  • 安全性高,秒级数据存储,出现意外最多丢失一秒的数据

AOF缺点

  • AOF是以Redis序列化协议存储的,同数据集体积下,RDB文件大小比AOF小很多

  • 由于AOF文件庞大, 数据恢复也会比RDB

总结

RDBAOF各有优势,如何选择得看业务场景。如果一秒的数据都不能丢,那么需要开启AOF。如果对于性能要求比较高并且能够承受几分钟的数据丢失,那么建议开启RDB。当然也有两种持久化方案都开启的情况。