Redis持久化机制
Redis持久化机制
RDB(Redis DataBase)快照 默认
概述
原理
在指定的时间间隔内对数据进行快照存储
保存这一时刻的数据状态
优点
数据恢复快,效率高
对数据完整性和一致性要求不高
缺点
数据容易丢失。因为是在一定间隔时间做一次备份,所以如果redis意外宕机,就会丢失最后一次快照后的所有修改
性能膨胀。Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性。
原理
Redis会单独fork一个子进程来进行持久化,先将数据写入到一个临时文件中(默认dump.rdb),待持久化过程结束,把这个临时文件替换上次持久化好的文件。在Fork过程中,主线程是阻塞的,但Fork完成后,主进程继续处理命令请求。
恢复时,将快照文件直接读到内存里进行恢复。
Fork
作用:复制一个与当前进程一样的进程
新进程的所有数据(变量,环境变量,程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。
rdb保存的文件默认是 dump.rdb
触发机制
客户端方式: bgsave 和 save指令
bgsave
Redis会调用fork来创建一个子进程,然后子进程负责将快照写入磁盘中,而父进程则继续处理命令请求。
可以通过lastsave
命令获取最后一次成功执行快照的时间
save
Redis服务器在快照创建完毕之前,redis处于阻塞状态,无法对外服务
自动触发
概述
如果用户在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
配置文件中
默认配置:
1分钟内改了1万次
5分钟内改了10次
15分钟内改了1次
若要修改完毕需要立马生效,可以手动使用 save 命令!立马生效 ! flushall也可以
其它方式
flushall命令
也会产生 dump.rdb 文件,但里面是空的,无意义 !
shutdown
当redis通过shutdown指令接收到关闭服务器的请求时,会执行一个save命令,阻塞所有的客户端,不再执行客户端执行发送的任何命令,并且在save命令执行完毕之后关闭服务器
正常退出redis
也会产生 dump.rdb 文件
如何恢复数据
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
禁用RDB持久化策略
只要不设置任何save指令,或者给save传入一个空字符串参数
修改快照生成位置
在redis.conf中,找到dir,修改即可
例如:dir ./
其余命令
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相同。
原理
流程
原理
将Redis执行过的写命令,通过write函数写入到缓冲区(aof_buf),然后再从缓冲区追加到日志文件(appendonly.aof
)末尾(只能追加文件)
恢复:Redis从头到尾执行一次AOF文件所包含的所有写命令,就能完成数据的恢复工作
注意
appendonly.aof
在bin
目录下
AOF不是立即写到磁盘中,可以通过配置修改文件强制写到磁盘中
流程
1、收到
bgrewriteaof
命令后,Redis调用fork ,获取子进程。子进程根据当前数据状态在内存中生成快照,然后将快照先写入
aof_buf
缓冲区,然后再向临时文件中写入父进程继续处理client请求,把写命令写入到原来的aof文件中,并同时写入到
aof_rewrite_buf
缓冲区(解决子线程重写失败、Redis数据修改数据不一致问题)
2、当子进程把快照内容以命令方式写到临时文件中后,子进程发信号通知父进程。然后父进程把
aof_rewrite_buf
缓冲区中的写命令写入到临时文件中,然后父进程使用临时文件替换老的aof文件,并重命名3、后面收到的写命令往新的aof文件中追加
文件重写(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文件中
触发机制
客户端:bgrewriteaof命令
手动触发:客户端命令
bgrewriteaof
命令 不会阻塞redis的服务
自动触发
概述
Redis会记录上次重写时的AOF文件大小,当AOF文件的大小超过所设定的阈值时,就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集
默认配置:当AOF文件大小是上次rewrite后大小至少一倍且文件大于64M时触发。
修改默认配置
配置redis.conf
中的auto-aof-rewrite-percentage
选项
比如,如果设置auto-aof-rewrite-percentage 100
、auto-aof-rewrite-min-size 64mb
,并且启用的AOF持久化时。
那么当AOF文件体积大于64M,并且AOF文件的体积比上一次重写之后体积大了至少一倍(100%)时,会自动触发。
如果重写过于频繁,可以考虑将auto-aof-rewrite-percentage
设置为更大
配置位置、开启AOF
redis.conf
开启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文件,载入较新的那个,微博就是这种架构。