Redis持久化

一、为什么需要持久化

由于redis是在内存中存储的,机器关机,数据就没了,而要想数据具有持久性,就必须持久化。而要想持久化,就必须如同MySQL一样,将数据保存至文件中。redis相比于MySQL而言,因为是在内存中存储的,效率会高很多,而要想效率高,又想持久化,就必须存两份,即内存和磁盘中各有一份!这两份数据理论上是完全相同的,实际上可能存在一个小概率有差异,取决于具体怎么进行持久化

当插入一个新的数据的时候,就需要把这个数据,同时写入到内存和磁盘;当查询某个数据的时候,直接从内存中读取

磁盘的数据只是在redis重启的时候,用来恢复内存中的数据的!

持久化的代价就是消耗了更多的空间,同一份数据,存储了两份,但磁盘比较偏移,这样的开销也并不会带来太多的成本

持久化策略

持久化策略有两种,RDB和AOF

二、RDB持久化

RDB:Redis DataBase的缩写,它是一种定期备份,即每隔一段时间,就把Redis内存中的所有数据都写入到磁盘中,生成一个"快照"

定期备份又有两种方式,分为手动触发和自动触发

手动触发

手动触发:程序员通过Redis客户端,执行特定的命令,来触发快照生成,有两个命令,分别是save和bgsave命令

save:执行save时,Redis就会全力以赴的进行"快照生成"操作,此时就会阻塞Redis中的其它客户端的命令,导致类似于keys *的后果,一般不建议使用save

bgsave:bg,即background(后面)的缩写,不会影响Redis服务器处理其它客户端的请求和命令,采用的是多进程的方式来完成bgsave的实现!

自动触发

自动触发:在Redis配置文件中,设置以下,让Redis每隔多长时间/每产生多少次修改就触发

如下图,是bgsave命令的执行流程图

在这里插入图片描述
如下图,redis生成的rdb文件,是存放在redis的工作目录中的,也是在redis配置文件中,进行设置的。rdb机制生成的镜像文件,二进制的文件,把内存中的数据,以压缩的形式保存到这个二进制文件中(需要消耗一定的cpu资源,但是能节省存储空间),redis服务器是默认就开启了rdb的
在这里插入图片描述
注意:这个文件不要乱改,一旦把数据的格式改坏了,就麻烦了,后续redis服务器重新启动,就会尝试加载这个rdb文件,如果发现格式错误,就可能会加载数据失败。当然,即使我们不去主动动它,但是也可能会出现一些意外的问题,一旦通过一些操作,比如网络传输,引起这个文件被破坏,此时redis服务器就会无法启动,redis也提供了rdb文件的检查工具

在这里插入图片描述
另外,redis的持久化操作,是可以触发多次的!!!

备份的具体做法

当执行生成rdb镜像操作的时候,此时就会把要生成的快照数据,先保存到一个临时文件中,当这个快照生成完毕之后,再删除之前的rdb文件,把新生成的临时的rdb文件名字改成刚才的dump.rdb。至始至终,rdb文件是始终只有一个的!

如下图,是rdb生成的持久化文件的名字
在这里插入图片描述
注意:redis文件中的数据,不是客户端插入了数据,就会立即更新的!

如下图,如果有至少一个key被修改,15分钟后才会被保存;如果有至少10个key被修改,5分钟后才会被保存;如果有至少10000个key被修改,60秒后才会被保存!

此处的这些数值,都是可以自由修改配置的,但是要有一个基本的原则,生成一次rdb快照,这个成本是一个比较高的成本,不能让这个操作执行的太频繁!!!

正因为rdb生成的不能太频繁,这就导致,快照里的数据,和当前实时的数据情况,可能存在偏差

在这里插入图片描述

实战演练

如下图,手动执行bgsave命令,触发一次生成快照,可以看到数据被保存到文件中了

在这里插入图片描述
在这里插入图片描述
如下图,不手动执行bgsave命令,可以看到新插入的数据,被保存至文件中了,服务器重启后,数据还存在,证明,数据是从文件中加载进内存的,这里引发了自动触发机制!

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果是服务器异常关闭,比如kill -9,服务器断电,此时,redis服务器来不及生成rdb,内存中尚未保存到快照中的数据就会丢失,如下图,当服务器进程被杀掉后,数据并没有被保存到文件中

在这里插入图片描述
在这里插入图片描述
如下图,根据文件的Inode编号的改变,可看出新的rdb文件会替换旧的rdb文件

在这里插入图片描述
注意:执行flusall命令,也会清空rdb文件!!!

rdb文件损坏

如果把rdb文件,故意改坏了,会咋样?

手动的把rdb文件内容改坏,然后一定是通过kill进程的方式,重新启动redis服务器,如果是通过service redis-server restart重启,就会在redis服务器退出的时候,重新生成rdb快照,就把刚才改坏了的文件给替换掉了!!!

在结尾位置修改了数据,可能不会出现问题,redis服务器还是能重启,但直接把坏了的rdb文件交给redis服务器去使用,得到的结果是不可预期的

改掉的是中间位置的数据时,就会导致redis服务器无法重启,如下图所示

在这里插入图片描述
在这里插入图片描述
查看日志文件(redis-server.log)

在这里插入图片描述
可以使用redis提供的rdb文件检查工具redis-check-rdb,检查rdb文件格式是否符合要求

在这里插入图片描述

RDB小结

RDB是⼀个紧凑压缩的⼆进制⽂件,代表Redis在某个时间点上的数据快照。非常适⽤于备份,全
量复制等场景。比如每6小时执行bgsave备份,并把RDB⽂件复制到远程机器或者文件系统中
(如hdfs)用于灾备。

Redis加载RDB恢复数据远远快于AOF的方式。

RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运⾏都要执行fork创建⼦进程,属于重量级操作,频繁执行成本过高。

RDB文件使⽤特定⼆进制格式保存,Redis版本演进过程中有多个RDB版本,兼容性可能有风险。

RDB最大的问题,不能实时的持久化保存数据

三、AOF持久化

AOF:Append Only File的缩写,当我插入了新的数据时,就立即把这个数据备份到磁盘中,类似于MySQL的binlog,会把用户的每个操作,都记录到文件中,当redis重新启动的时候,就会读取这个AOF文件中的内容,用来恢复数据,默认是关闭状态,将no改为yes即开启,不过需要重新启动redis服务器才能生效

在这里插入图片描述
对于无法解决在两次快照之间,实时的数据可能会随着重启而丢失的问题,AOF可以去解决,与RDB不同的是,它是一个文本文件

如下图,执行的操作都被aof文件保存下来了,通过一些特殊符号作为分隔符,来对命令的细节做出区分

在这里插入图片描述
在这里插入图片描述
引入AOF之后,又要写入内存,又要写磁盘,还能和之前一样快吗?

实际上,是没有影响的!并没有影响到redis处理请求的速度,原因如下:

1、AOF机制并非是直接让工作线程把数据写入磁盘,而是先写入一个内存中的缓冲区,积累一波后,再统一写入磁盘,这样就大大降低了写入磁盘的次数

2、磁盘上读写数据,顺序读写相比于随机访问速度是比较快的,AOF是每次把新的操作写入到原有文件的末尾,属于顺序写入

缓冲区的刷新策略

不过写入内存缓冲区,也是有风险的,比如进程挂了或者是机器断电了,缓冲区中的数据也就丢了,redis给出了一些选项,根据实际情况,来决定怎么取舍

在这里插入图片描述
always:命令写入aof_buf后,调用fsync同步,完成后返回。频率是最高的,数据可靠性最高,性能最低

everysec:命令写入aof_buf后,只执行write操作,不进行fsync,每秒由同步线程进行fsync。频率低一些,数据可靠性也会降低,性能会提高

no:命令写入aof_buf后,只执行write操作,由OS控制fsync频率。频率最低,数据可靠性也是最低的,性能是最高的

重写机制

AOF文件持续增长,体积越来越大,会影响到redis服务器下次的启动时间,因为redis服务器启动的时候,要读取aof文件的内容,该文件记录了中间的过程,实际上redis在重新启动的时候,只会关注最终结果,比如lpush key 111,lpush key 222,lpush key 333,又比如set key 111,set key 222,set key 333,redis都只会关注lpush key 111 222 333和set key 333。因为redis存在一个机制,能够针对aof文件进行整理操作,这个整理就是能够剔除其中的冗余操作,并且合并一些操作,达到给aof文件瘦身的效果

AOF重写过程可以分为手动触发和自动触发

⼿动触发:调⽤bgrewriteaof命令。

⾃动触发:根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数确定自动触发时机。
auto-aof-rewrite-min-size:表⽰触发重写时AOF的最大文件大小,默认为64MB。
auto-aof-rewrite-percentage:代表当前AOF占用大小相比较上次重写时增加的比例。

如下图,是AOF重写的流程。父进程仍然负责接收请求,子进程负责针对aof文件进行重写,把内存中当前的数据,获取出来,以aof的格式写入到一个新的aof文件中。

注意:内存中的数据的状态,就已经相当于是把AOF文件结果整理后的模样了

注意:重写的时候,不关心aof文件中原来都有些什么,只关心内存中最终的数据状态!!!
在这里插入图片描述
子进程写新的AOF文件的同时,父进程仍然在不停的接收客户端的新的请求,父进程还是会把这些请求产生的AOF数据,先写入到缓冲区,再刷新的原有的AOF文件里

在创建子进程的一瞬间,子进程就继承了当前父进程的内存状态,因此,子进程里的内存数据是父进程fork之前的状态,fork之后,新来的请求,对内存造成的修改,子进程是不知道的。父进程又准备了一个aof_rewrite_buf缓冲区,专门存放fork之后收到的数据,子进程这边,把aof数据写完之后,会通过信号通知父进程,父进程再把aof_rewrite_buf缓冲区中的内容也写入到新AOF文件中,此时,就可以用新的AOF文件代替旧的AOF文件了

如果在执行bgrewriteaof的时候,当前redis已经正在进行aof重写了,此时,就不会再次执行aof重写,而是直接返回了

如果在执行bgrewriteaof的时候,发现当前redis在生成rdb文件的快照,此时,aof重写操作就会等待,等待rdb快照生成完毕之后,再执行aof重写

父进程fork完毕之后,就已经让子进程写新的aof文件了,并且随着时间的推移,子进程很快就写完了新的文件,要让新的aof文件代替旧的,还让父进程继续写这个即将消亡的aof文件是否还有意义?

在某些极端情况下,是很有必要的,假设在重写过程中,重写了一半了,服务器挂了,子进程内存的数据就会丢失,新的aof文件内容还不完整,所以如果父进程不坚持写旧aof文件,重启就没办法保证数据的完整性了

四、混合持久化

AOF本来是按照文本的方式来写入文件的,但是文本的方式写文件,后续加载的成本是比较高的,所以就结合了rdb和aof的特点,引入了混合持久化

按照aof的方式,每一个请求/操作,都记录至文件,在触发aof重写之后,就会把当前内存的状态按照rdb的二进制格式写入到新的aof文件中,后续再进行的操作,仍然是按照aof文本的方式追加到文件的末尾

如下图,把配置文件中的这个改为yes,就表示开启混合持久化了

在这里插入图片描述
当redis上同时存在aof文件和rdb快照的时候,此时,以aof为主,rdb就被忽略了

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值