Redis持久化机制

RDB(Redis DataBase)快照 默认

概述

原理

在指定的时间间隔内对数据进行快照存储

保存这一时刻的数据状态

image-20210202200950668

优点

  • 数据恢复快,效率高

  • 对数据完整性和一致性要求不高

缺点

  • 数据容易丢失。因为是在一定间隔时间做一次备份,所以如果redis意外宕机,就会丢失最后一次快照后的所有修改

  • 性能膨胀。Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性。

image-20200614215240639

原理

Redis会单独fork一个子进程来进行持久化,先将数据写入到一个临时文件中(默认dump.rdb),待持久化过程结束,把这个临时文件替换上次持久化好的文件。在Fork过程中,主线程是阻塞的,但Fork完成后,主进程继续处理命令请求。

恢复时,将快照文件直接读到内存里进行恢复。

image-20200614214437148

Fork

作用:复制一个与当前进程一样的进程

新进程的所有数据(变量,环境变量,程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。

rdb保存的文件默认是 dump.rdb

image-20200614214821794

触发机制

客户端方式: bgsave 和 save指令

bgsave

Redis会调用fork来创建一个子进程,然后子进程负责将快照写入磁盘中,而父进程则继续处理命令请求。

可以通过lastsave命令获取最后一次成功执行快照的时间

image-20210202201632786

save

Redis服务器在快照创建完毕之前,redis处于阻塞状态,无法对外服务

image-20210202201645634

自动触发

概述

如果用户在redis.conf中设置了save配置选项,redis会在save选项条件满足之后自动触发一次BGSAVE命令

如果设置多个save配置选项,当任意一个save配置选项条件满足,Redis也会触发一次BGSAVE命令

格式

 save 多少秒内 多少个key发生变化

示例

 save 120 10  # 如果120秒内超过10个key发生变化,则触发RDB
 save 900 1   # 如果900秒内超过1个key发生变化,则触发RDB

配置位置

redis.conf配置文件中

image-20200614215320978

默认配置:

  • 1分钟内改了1万次

  • 5分钟内改了10次

  • 15分钟内改了1次

若要修改完毕需要立马生效,可以手动使用 save 命令!立马生效 ! flushall也可以

其它方式

flushall命令

也会产生 dump.rdb 文件,但里面是空的,无意义 !

shutdown

当redis通过shutdown指令接收到关闭服务器的请求时,会执行一个save命令,阻塞所有的客户端,不再执行客户端执行发送的任何命令,并且在save命令执行完毕之后关闭服务器

正常退出redis

也会产生 dump.rdb 文件

image-20200614215948504

如何恢复数据

1、将备份文件(dump.rdb)移动到redis安装目录并启动服务即可

2、config get dir 获取目录

 127.0.0.1:6379> config get dir
 dir
 /usr/local/bin   # 如果在这个目录下存在 dump.rdb文件 ,启动就会自动恢复其中的数据

其它设置项

修改默认名称

步骤

在redis.conf中,找到dbfilename,修改即可

示例

dbfilename dump.rdb

image-20210202202239785

禁用RDB持久化策略

只要不设置任何save指令,或者给save传入一个空字符串参数

修改快照生成位置

在redis.conf中,找到dir,修改即可

例如:dir ./

image-20210202202304719

其余命令

Stop-writes-on-bgsave-error

如果配置为no,表示你不在乎数据不一致或者有其他的手段发现和控制,默认为yes。

rbdcompression

对于存储到磁盘中的快照,可以设置是否进行压缩存储。

如果是的话,redis会采用LZF算法进行压缩,如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能。

rdbchecksum

在存储快照后,还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。默认为yes。

AOF(Append Only File)

概述

原理

将所有redis写命令(增加、删除、修改)记录到日志文件中

记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据

Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。

优点

缓存一致性高,数据不易丢失

1、每一次修改都同步:appendfsync always 同步持久化,每次发生数据变更会被立即记录到磁盘,性能较差但数据完整性比较好

2、每秒同步一次: appendfsync everysec 异步操作,每秒记录 ,如果一秒内宕机,有数据丢失

3、不同步: appendfsync no 从不同步 效率最高

缺点

1、恢复速度慢。相同数据集的数据而言,aof 文件要远大于 rdb文件,恢复速度慢于 rdb。

2、Aof 运行效率要慢于 rdb,每秒同步策略效率较好,不同步效率和rdb相同。

image-20200614220733693

原理

流程

原理

将Redis执行过的写命令,通过write函数写入到缓冲区(aof_buf),然后再从缓冲区追加到日志文件(appendonly.aof)末尾(只能追加文件)

恢复:Redis从头到尾执行一次AOF文件所包含的所有写命令,就能完成数据的恢复工作

image-20210202202709755

注意

appendonly.aofbin目录下

AOF不是立即写到磁盘中,可以通过配置修改文件强制写到磁盘中

流程

  • 1、收到bgrewriteaof命令后,Redis调用fork ,获取子进程。

    • 子进程根据当前数据状态在内存中生成快照,然后将快照先写入aof_buf缓冲区,然后再向临时文件中写入

    • 父进程继续处理client请求,把写命令写入到原来的aof文件中,并同时写入到aof_rewrite_buf缓冲区(解决子线程重写失败、Redis数据修改数据不一致问题)

  • 2、当子进程把快照内容以命令方式写到临时文件中后,子进程发信号通知父进程。然后父进程把aof_rewrite_buf缓冲区中的写命令写入到临时文件中,然后父进程使用临时文件替换老的aof文件,并重命名

  • 3、后面收到的写命令往新的aof文件中追加

image-20200614221040327

image-20210202205051092

文件重写(aof重写)

作用

因为AOF 采用文件追加方式,文件会越来越大。

例如:我们调用incr test命令100次,文件中必须保存全部的100条命令,其实有99条都是多余的。因为文件中只需保存一条set test 100就够了

为了压缩aof的持久化文件,Redis提供了AOF重写(ReWriter)机制

实现

fork出1个子进程来实现这件事

注意

重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,替换原有的文件。

这点和快照有点类似。

aof重写数据不一致问题

子进程在重写期间,如果Redis修改了数据。就会出现和重写的内容不一致的情况

解决:准备一个aof重写缓冲区(aof_rewrite_buf),重写子线程开始后,主进程把后续的写命令copy一份到重写缓冲区中,子进程重写文件结束后,把缓冲区中的命令写入新的aof文件中

image-20221107下午113604140

触发机制

客户端:bgrewriteaof命令

手动触发:客户端命令

bgrewriteaof命令 不会阻塞redis的服务

自动触发

概述

Redis会记录上次重写时的AOF文件大小,当AOF文件的大小超过所设定的阈值时,就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集

默认配置:当AOF文件大小是上次rewrite后大小至少一倍且文件大于64M时触发。

修改默认配置

配置redis.conf中的auto-aof-rewrite-percentage选项

比如,如果设置auto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 64mb,并且启用的AOF持久化时。

那么当AOF文件体积大于64M,并且AOF文件的体积比上一次重写之后体积大了至少一倍(100%)时,会自动触发。

如果重写过于频繁,可以考虑将auto-aof-rewrite-percentage设置为更大

image-20210202204433928

配置位置、开启AOF

redis.conf

image-20200614220358591

开启AOF

 appendonly no # 是否以append only模式作为持久化方式,yes 开启
 ​
 appendfilename "appendonly.aof"  # appendfilename AOF 文件名称

日志追加频率

哪里配置

redis.conf中的appendfsync everysec 持久化策略的配置

no

由操作系统决定何时同步,性能最好,但持久化没保证.系统崩溃时,会丢失不定数量的数据

如果用户硬盘处理写入操作不够快的话,当缓冲区被等待写入硬盘数据填满时,redis会处于阻塞状态,并导致redis的处理命令请求的速度变慢。

always

每个redis写命令都要同步写入硬盘,效率最差,但能保证完全的持久化。redis处理命令的速度会受到硬盘性能的限制

everysec 推荐

让redis每秒一次的频率对AOF文件进行同步,在性能和持久化方面做了平衡

即使系统崩溃,用户最多丢失一秒之内产生的数据。

其它配置
 No-appendfsync-on-rewrite no      # 重写时是否可以运用Appendfsync,用默认no即可,保证数据安全性
 ​
 Auto-aof-rewrite-percentage  100  # 设置重写的基准值   了解
 Auto-aof-rewrite-min-size 64mb    # 设置重写的基准值  了解
 ​
 aof-load-truncated yes
 aof-use-rdb-preamble yes

如何恢复数据

正常恢复

  • 启动:设置Yes。修改默认的appendonly no,改为yes

  • 将有数据的aof文件复制一份保存到对应目录(config get dir)

  • 恢复:重启redis,然后重新加载

异常恢复

  • 启动:设置Yes

    • 模拟异常:故意破坏 appendonly.aof 文件!随便添加一些东西

  • 修复:redis-check-aof --fix appendonly.aof进行修复

  • 恢复:重启 redis,然后重新加载

对比

时效性

  • RDB:分钟级别

  • AOF:秒级

效率

如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。

注意

如果只启用一个并且切换了持久化策略,那么原有的数据就不会在另一个策略中。

如何选择持久化策略?

概述

业务上是允许重启时部分数据丢失的,那RDB就够用了

对时效性、一致性要求高,AOF

实际开发

两个都启用

在Redis4.0以后也支持了AOF和RDB混合。

bgsave做镜像全量持久化,aof做增量持久化。

因为bgsave会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据,所以需要aof来配合使用。

在redis实例重启时,会使用bgsave持久化文件重新构建内存,再使用aof重放近期的操作指令来实现完整恢复重启之前的状态。

先用RDB恢复到之前的状态,以时间为节点进行后续的AOF操作

同时开启两种持久化方式

  • 当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。

  • RDB 的数据不实时,同时使用两者时,服务器重启也只会找AOF文件,那要不要只使用AOF呢?

    • 不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有AOF可能潜在的Bug,留着作为一个万一的手段

性能建议

  • 因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留 save 900 1 这条规则。

  • 如果Enable AOF ,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了,代价一是带来了持续的IO,二是AOF rewrite 的最后将 rewrite 过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上,默认超过原大小100%大小重写可以改到适当的数值。

  • 如果不Enable AOF ,仅靠 Master-Slave Repllcation 实现高可用性也可以,能省掉一大笔IO,也减少了rewrite时带来的系统波动。代价是如果Master/Slave 同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个 Master/Slave 中的 RDB文件,载入较新的那个,微博就是这种架构。

参考资料

趣话Redis第二弹 Redis数据持久化AOF和RDB原理一次搞懂