Redis的持久化

目录

redis实现持久化的策略

RDB持久化

RDB定期备份的两种方式

RDB自动触发的条件

AOF

aof重写机制

aof重写流程

混合持久化


redis是一个内存数据库,是把数据存储在内存中的,而我们知道内存中的数据是不持久的,一旦服务器重启或者进程重启,内存的数据就丢失了.为了让数据达到持久化的效果,就必须把数据写到硬盘上.

redis相对于mysql这样的关系型数据库最明显的优势就是快.所以为了保证速度快,数据还得在内存中,但是为了持久,数据还要想办法存储在硬盘上.

Redis为了应对这样的情况,决定把数据在内存中存储一份,同时在硬盘上也存储一份.这样的两份数据,理论上是完全相同的,实际上可能存在差异,取决于我们具体怎么进行持久化.

当要插入一个新的数据的时候,就需要把这个数据,同时写入内存和硬盘.但说是同时写,实际上怎么写入硬盘是有不同的策略的,应用这些策略,就可以保证redis整体的效率还是足够高的.

当查询某个数据的时候,直接从内存读取.硬盘中的数据只是在redis重启的时候,用来回复内存中的数据的.

代价就是消耗了更多的空间,同一份数据存储了两份,但是硬盘空间毕竟是比较廉价的,这样的开销并不会带来很多的成本.


redis实现持久化的策略

redis实现持久化的整体策略有两种,RDB和AOF.

RDB:Redis DataBase.AOF:Append Only File.

RDB是定期备份,AOF是实时备份.

RDB持久化

RDB持久化是定期的把当前进程数据生成快照保存到硬盘的过程.

后续redis一旦重启了,就可以根据硬盘的中快照把内存中的数据给回复回来.

RDB定期备份的两种方式

1.手动触发

程序员通过redis客户端,执行特定的命令,来触发快照的生成.

save命令,执行save命令的时候,redis服务器会在单线程模型下全力以赴的进行快照生成的操作,此时就会阻塞redis其他客户端的命令,一般不建议使用save.

bgsave,bg是background的缩写,此命令不会影响redis服务器处理其他客户端的请求和命令.此命令是redis通过多进程的方式来完成并发编程从而实现bgsave.

2.自动触发

我们可以在redis配置文件中,设置一下,让redis每隔多长时间以及每产生多少次修改就触发备份操作.

redis生成rdb文件,是存放在redis的工作目录中的,redis的工作目录也是在redis配置文件中进行设置的.

我们不仅可以修改redis的工作目录,也可以修改生成的rdb文件的名字.

dump.rdb是RDB机制生成的镜像文件,redis服务器默认是开启了rdb的.此rdb文件时一个二进制的文件,把内存中的数据,以压缩的形式,保存到这个二进制文件中.(压缩会消耗一定的cpu资源,但是能节省存储空间).

这个二进制文件,我们不能随意修改.redis服务器重新启动,会尝试加载这个rdb文件,如果发现格式错误,就可能会加载数据失败.

需要注意的是,rdb文件,即使我们不去主动修改它,但是也可能会出现一些意外情况,一旦通过一些操作(比如网络传输)引起这个文件被破坏,此时redis服务器也是无法正常启动的.

rdb的持久化操作可以执行多次,当执行生成rdb镜像文件操作的时候,此时就会把要生成的快照数据,先保存到一个临时文件中,当这个快照生成完毕之后,在删除之前的rdb文件,把新生成的rdb临时文件名字改为刚才的dump.rdb,所以自始至终,rdb文件是始终只有一个的.


RDB自动触发的条件

我们可以在redis的配置文件中查看达到自动触发rdb的条件. 

15分钟之后如果至少修改了一次或者5分钟之后至少修改了10次或者1分钟之后至少修改了10000次就会自动触发rdb机制.

注意:时间要满足的同时修改次数也要满足.

此处的数值都可以自行修改.但是修改上述的数据的时候,要有一个基本的原则:生成一个rdb快照,是一个比较高的成本,不能让这个操作执行的太过频繁.

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


手动执行bgsave触发一次生成快照

由于这里的数据比较少,执行bgsave瞬间就完成了,立即查看应该是有结果的.如果这里的数据比较多,执行bgsave就可能需要消耗一定的时间,立即查看不一定就是生成完毕了.

在rdb镜像文件里可以隐约的看到我们的插入的key.

我们重启redis服务器,再次进入redis客户端查看数据.

通过上述操作,就可以看到,redis服务器在重启的时候,加载了rdb文件的内容,恢复了之前内存中的数据状态.


插入新的key,不手动执行bgsave

我们插入一个新的key之后,重新启动redis服务器,再次查看内容.

可以看到我们新插入的key4依然存在,但是我们并没有手动执行bgsave,同时也没有达到自动触发的条件,这是什么原因呢?

这是因为如果是通过正常流程重新启动redis服务器,此时redis服务器会在退出的时候自动触发生成rdb的操作.但是如果是异常重启(kill -9或者服务器掉电),此时redis服务器来不及生成rdb,内存中尚未保存的数据就会随着redis启动而真的丢失了!!!

所以redis自动触发rdb会在多个场景中存在:

1.在配置文件中配置save 时间 次数,表示在多长时间之后,执行次数达到多少,才触发.

2.通过shutdown命令(不带参数),关闭redis服务器,此处的关闭属于是正常关闭,也会触发生成rdb快照的操作.我们上述的service redis-server restart也属于是正常关闭.

3.redis进行主从复制的时候,主节点也会自动生成rdb快照,然后把rdb快照文件内容传输给从节点.

如果正常情况的关闭,我们是不必担心内存数据丢失的情况,在实际开发中我们更担心异常情况的出现导致redis服务器异常关闭.比如使用kill命令(kill -9 redis进程id)的方式来直接杀死redis进程,此时就会导致新插入的数据的丢失.

注意在ubuntu系统下,由于我们是通过service的方式来启动redis,所以会存在一个守护进程来时刻检测redis的情况,当redis服务器挂掉之后,会迅速在拉起一个redis,所以虽然kill掉了redis进程,但是查看进程信息redis还存在,但是此时的进程id已经不一致了.


bgsave操作流程是创建子进程,由子进程完成持久化操作.

持久化会把数据写入到一个新的临时文件中,最后使用新的文件来代替旧的文件.

如果直接使用save命令,此时是不会创建子进程和进行文件替换的.save命令是直接在当前进程中,往同一个文件中写入数据,不会创建新的文件.

inode相当于是文件的标识,inode不同,说明文件已经不是同一个文件了.


通过配置自动生成rdb快照

我们可以在配置文件中修改save来设置自动生成快照的条件.对于redis来说,修改配置文件之后,一定要重启服务器,才能生效,如果想要立即生效,也可以通过命令的方式修改.

save " "是用来关闭自动生成快照的.


当我们把rdb的文件改坏了,会发生什么

手动的把rdb的文件改坏,然后一定是通过kill进程方式,重新启动redis服务器.

如果是通过service redis-server restart重启,就会在服务器退出的时候,重新生成rdb快照,就把刚才改坏掉的文件替换掉了,所以要使用kill的方式.

由于rdb文件时二进制的,直接把改坏掉的rdb文件交给redis服务器去使用,得到的结果是不可预期的.

如果改的地方正好是文件末尾,对前面的内容没有影响,可能redis再次启动还是可以恢复正常的数据的.

对于rdb文件损坏,可能redis服务器启动得到的数据正确性可能有问题,也可能redis服务器直接就启动失败了.

redis也提供了rdb文件的检查工具,可以先通过检查工具,检查一下rdb的文件格式是否是符合要求的.


AOF

当开启aof的时候,rdb就不生效了,reids服务器启动的时候就不再读取rdb文件的内容了.

会把用户的每个操作都记录到文件中.当redis重新启动的时候,就会读取这个aof文件中的内容,用来恢复数据.

aof默认一般是关闭状态,修改配置文件,来开启aof功能.

修改为yes开启.

aof文件所在的位置和rdb文件在同一目录下.(/var/lib/redis)

aof是一个文本文件,每次进行的操作都会记录到文本文件中,通过一些特殊符号作为分隔符,对命令的细节做出区分.

引入aof之后,既要写内存又要写硬盘,redis是不是就变慢了?

redis是一个单线程的服务器,速度很快(快就快在直接操作内存).引入aof之后,实际上对于redis来说,是没有影响的.并没有影响redis处理请求的速度.原因有两点:

1.aof机制并非是直接让工作线程将数据写入硬盘,而是先写入一个内存中的缓冲区,当缓冲区的数据积累到一定量之后,在统一写入内存.引入缓冲区之后,就大大降低了写硬盘的次数.写硬盘的时候,写入硬盘数据的多少,对于性能的影响不是很大,关键是写硬盘的次数多了,影响就比较大了.

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


如果把数据写入到缓冲区里,本质还是在内存中,如果这个时候,进程突然崩溃或者主机掉电,缓冲区中的数据还没来得及写入到硬盘中,那么这一部分数据就丢失了.

所以,redis给出了一些选项,来取舍刷新频率和性能.

刷新频率越高,那么对性能的影响就越大,但是数据的可靠性就越高.

刷新频率越低,性能影响的越小,但是数据的可靠性就越低.


aof重写机制

当aof文件持续增长,体积就会越来越大,会影响到redis下次启动时的启动时间.

为了解决这个问题,就出现了重写机制.

重写机制是因为在zof文件中,有一些内容是冗余的,比如对一个key修改了多次,但是我们在下次启动的时候,只是关注这个key的最终结果的,至于它是修改了几次我们是不关注的,比如删除一个key,或者set了多个key我们可以用mset命令.

重写其实就是对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重写流程

父进程通过fork操作创建出子进程.

父进程仍然负责接收请求,子进程负责针对aof文件重写.在重写的时候,不关心aof文件中原来的内容,只是关心内存中最终的数据状态.

子进程只需要把内存中当前的数据,获取出来,以aof的格式,写入到一个新的aof文件中.(内存中的数据状态,就已经相当于是aof文件结果整理后的模样了).

子进程写新的aof文件的同时,父进程仍然在不停的接收客户端的请求,父进程还是会把这些请求产生的aof数据先写入到缓冲区,在刷新到原有的aof文件中.

在创建子进程的瞬间,子进程就继承了当前父进程的内存状态.因此,子进程里的内存数据是父进程fork之前的状态,fork之后,新来的请求对内存造成的影响,是子进程感知不到的.

所以,此时父进程又准备了一个aof_rewrite_buf缓冲区,专门用来存放fork之后收到的数据.当子进程把aof数据写完之后,会通过信号通知父进程,父进程在把aof_rewrite_buf中的内容也写入到新的aof文件里.

此时就可以用新的aof文件代替旧的文件了.


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

如果,在执行bgrewriteaof的时候,当前redis正在生成rdb文件的快照,那么aof操作就会等待,等到rdb快照生成完毕之后,在进行执行aof操作.

rdb对于fork之后的数据,就直接置之不理了.aof则对于fork之后的数据,采取了aof_rewrite_buf缓冲区的方式来处理.这也很符合它们的设计理念.rdb只是用来定期备份(定期备份就难以和最新的数据保持一致),aof则是实时备份.

父进程fork完毕之后,就已经让子进程写新的aof文件了,并且一段时间过后,子进程很快的完成了工作,新的文件代替旧的文件.那么,父进程还有必要继续写这个即将被替换的旧的文件吗?

是有必要的.考虑到极端情况,假设在重写过程中,重写到一半,服务器崩溃了,子进程内存的数据就丢失了,而新的aof文件内容还不完整,所以如果父进程不坚持写旧的aof文件,在这种情况下,reids重启就无法保证数据的完整性了.


混合持久化

aof本来是按照文本的方式来写入文件的,但是文本的方式写文件,后续加载的成本是比较高的.

此时redis就引入了混合持久化的方式,结合rdb和aof的特点.

按照aof的方式,每一个请求或者操作都会记录到文件中.

在触发aof重写之后,就会把当前的内存状态按照rdb的二进制格式写入到新的aof文件,后续再进行的操作,仍然是按照aof文本的方式追加到aof文件后面.

yes表示开启混合持久化.


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值