Redis的持久化简述

92 阅读6分钟

Redis的持久化简述

持久化

  • Redis支持数据的持久化,主要分为两种方式,分别是RDB和AOF。并且支持这两种的混合模式
  • Redis是"先写内存后刷盘"类型的数据库,即Redis先执行命令,把数据先写入内存,然后才记录日志文件

RDB模式

简述

  • Redis DataBase(快照/内存快照,缩写RDB)
  • RDB持久化是把当前进程数据生成快照保存到磁盘上的过程,由于是某一时刻的快照,那么快照中的值要早于或者等于内存中的值

相关配置

#自动触发持久化
save <seconds> <changes>

#开启RDB,如果配置的save "",则是关闭RDB
save m n


#RDB文件名称
dbfilename dump.rdb

#文件保存路径
dir /data/redis/data/

#是否压缩,Redis官方的建议是请保持该选项设置为yes
rdbcompression yes


#导入时是否检查,这个功能大概会多损失10%左右的性能,但获得了更高的数据可靠性。
#如果您的Redis服务需要追求极致的性能,就可以将这个选项设置为no
rdbchecksum yes

触发方式

自动触发

  • redis.conf中配置save m n。即在m秒内有n次修改时,自动触发bgsave生成rdb文件
  • 主从复制时,从节点要从主节点进行全量复制时,也会触发bgsave操作,生成当时的快照发送到从节点
  • 执行debug reload命令重新加载redis时也会触发bgsave操作
  • 默认情况下执行shutdown命令时,如果没有开启aof持久化,那么也会触发bgsave操作

手动触发

  • 通过调用save、bgsave命令进行

相关命令

  • save
    • 阻塞当前Redis服务器,直到RDB过程完成为止,对于内存 比较大的实例会造成长时间阻塞,线上环境不建议使用
  • bgsave
    • Redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短

持久化流程

  1. 主进程fork一个子进程,并与子进程共享此时的内存快照(fork之后主进程上的修改对子进程不可见)
  2. 子进程开始将内存快照写入dump.rdb文件中
  3. 在fork子进程后,主进程修改了任何数据,同时会将该数据拷贝一个副本,之后交给子进程一并写入dump.rdb文件中。即copy-on-write
  4. 将dump.rdb文件替换旧的文件,并完成持久化

刷盘(持久化)注意事项

  • 避免频繁的执行全量快照
    • 频繁将全量数据写入磁盘,会给磁盘IO带来很大压力,多个快照竞争有限的磁盘带宽,前一个快照还没有做完,后一个又开始做了,容易造成恶性循环
    • 容易造成主线程阻塞,在for子进程的时候会阻塞主线程

优缺点分析

  • 优点
    • RDB文件是某个时间节点的快照,默认使用LZF算法进行压缩,压缩后的文件体积远远小于内存大小,适用于备份、全量复制等场景
    • Redis加载RDB文件恢复数据要远远快于AOF方式
  • 缺点
    • RDB方式实时性不够,无法做到秒级的持久化
    • 每次调用bgsave都需要fork子进程,fork子进程属于重量级操作,频繁执行成本较高
    • RDB文件是二进制的,没有可读性,AOF文件在了解其结构的情况下可以手动修改或者补全
  • 数据持久化一致性处理方式(Copy-on-Write)
    • 读取数据写入快照
    • 更新的数据复制该数据的副本,当写入快照完成之后,再将副本数据写入快照

AOF模式

简述

  • AOF(Append Only File),通过追加的方式记录的Redis执行成功的写入命令,以文本形式保存的日志,是可读的
  • 是写后日志。即命令执行成功之后,再将该命令记录到日志中
  • 当开启了AOF之久化功能时,每当执行成功的写入命令后,会以协议格式将执行的命令追加到AOF_Buffer缓冲区,并通过指定的刷盘策略进行持久化
  • 以追加的形式记录日志,需要指定日志文件的重写方式来限制日志文件的大小

相关配置

#开启AOF持久化,默认情况下AOF功能是关闭的
appendonly no

#AOF持久化的文件名
appendfilename "appendonly.aof"

#同步策略
appendfsync everysec

#aof重写期间是否同步
no-appendfsync-on-rewrite no

#如果当前AOF文件的大小超过了,上次重写后AOF文件的百分之n后,就再次开始重写AOF文件
auto-aof-rewrite-percentage 100

#启动AOF文件重写操作的AOF文件最小大小。如果AOF文件大小低于这个值,则不会触发重写操作,默认为64MB
auto-aof-rewrite-min-size 64mb

#加载aof出错如何处理
aof-load-truncated yes

#文件重写策略
aof-rewrite-incremental-fsync yes

刷盘策略

  • Always(同步写回)
    • 每个写命令执行完,同时将命令写入到AofBuffer,然后将日志刷入磁盘
    • 繁调刷盘,可能导致I/O卡顿的现象频繁
  • Everysec(每秒写回)
    • 每个写命令执行完,同时将命令写入到AofBuffer,然后每隔一秒把缓冲区中的内容写入磁盘
    • 建议使用everysec,出现故障时最多丢失1秒的数据
  • No(操作系统控制的写回)
    • 每个写命令执行完,同时写入到AofBuffer,由操作系统决定何时将缓冲区内容写回磁盘

为什么采用写后日志

  • 避免额外的检查开销
  • 不会阻塞当前的写操作
  • 如果命令执行完成,写日志之前宕机了,会丢失数据
  • 主线程写磁盘压力大,导致写盘慢,阻塞后续操作

重写流程

主进程fork子进程(bgRewriteAof)后

  • 主进程
    1. 继续处理新的写入命令,并记录到两个(旧、新)日志文件Aof_Buffer缓冲区
    2. 将执行成功的命令写入到旧的AOF日志文件中
  • 子进程
    1. 把数据转为写指令存入新的AOF文件。(记录的是每个数据的最后一次写指令,也就是最新的数据,不会记录之前冗余的操作,可以很大程度的缩小AOF的体量)
    2. 将Aof_buffer缓冲区的日志写入AOF文件
    3. 将新的AOF文件替换旧的AOF文件
    4. 完成重写

混合模式(4.0版本增加)

Redis 4.0 中提出了一个混合使用 AOF 日志和RDB快照的方法。简单来说,RDB快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作