Redis:AOF日志和RDB快照

【关于作者】

关于作者,目前在蚂蚁金服搬砖任职,在支付宝营销投放领域工作了多年,目前在专注于内存数据库相关的应用学习,如果你有任何技术交流或大厂内推及面试咨询,都可以从我的个人博客(https://0522-isniceday.top/)联系我

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uWuXfwgq-1680881423364)(https://zhangyuxiangplus.oss-cn-hangzhou.aliyuncs.com/boke/数据持久化.png[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-saWGcvad-1680881423465)(https://zhangyuxiangplus.oss-cn-hangzhou.aliyuncs.com/boke/数据持久化.png)]]

fork:

redis的持久化主要包括两种,AOF日志和RDB快照

1.AOF日志

1.1.概念

AOF属于写后日志,就是说在处理完请求将数据存入内存之后才进行写日志操作。

img

1.2.AOF日志中的存储内容

我们已一条redis命令为例子:set testkey testvalue

再看看针对该条请求,日志中存储的内容

*3:表示命令有三个内容

3 s e t : 表示 s e t 有三个字节( 3 set:表示set有三个字节( 3set:表示set有三个字节(x,x代表字节数)

img

1.3.写后日志的优缺点

优点

(1)由于是先执行,再记录,因此不会出现语法错误的情形

(2)命令执行后才记录,不会阻塞当前请求

缺点

(1)可能会出现日志还没来得及写redis就宕机了,这样就会产生数据丢失

(2)虽然redis不会阻塞当前请求,由于redis是单线程的,因此有可能数据量比较大导致写日志缓慢,从而阻塞之后的请求

从缺点中我们能知道都是由于AOF写入的时机导致的,如果能控制写入的时机是不是就不会产生这些缺点了呢?

1.4.三种写回策略(AOF写入时机)

  • Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘;
  • Everysec,每秒写回:每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;
  • No,操作系统控制的写回:每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。

针对避免主线程阻塞和减少数据丢失问题,三种策略都不完美

比较如下:

img

1.5.AOF重写机制(日志文件过大怎么办?)

重写机制:会根据目前数据库的现状,创建一个新的AOF文件

6528c699fdcf40b404af57040bb8d208

这样,就将6条命令,重写为了1条命令就可解决,那么这个重写过程会阻塞主进程吗?不会(但是在fork这个时刻会)

具体实现

重写过程是由后台线程bgrewriteaof来完成的,这是为了避免阻塞主进程

(1)Redis执行fork(),现在同时拥有父进程和子进程

(2)子进程开始将新AOF文件的内容写到临时文件

(3)对于所有新执行的写入命令,父进程一边将他们存入当前AOF文件的内存缓冲中,一边将改动追加到现有的文件末尾

(4)当子进程完成重写工作时给父进程发送一个信号,父进程收到信号后,将步骤(3)内存缓冲中的数据追到到重写AOF的末尾

总结:“一个拷贝,两处日志

一个拷贝:执行重写时,主线程fork出子进程bgrewriteaof,并将内容拷贝一份给子线程去重写(涉及到fork()的写实复制(Copy On Write)机制),因此就可以做到不影响主线程去拷贝日志

两处日志:

由于重写并不会影响主线程,因此主线程仍然可以处理请求,当碰到写请求时,会写入当前AOF日志(第一处日志)的缓存区,所以即使redis宕机了也存有最新的日志用于恢复数据

第二处日志是指上述主线程的写请求也会写入AOF重写日志的缓存区,等到拷贝数据的所有操作记录重写完成后,再将该缓存区内的记录写入新的AOF日志文件用于保证数据是最新的,最后替代重写前的日志文件

img

重写过程的阻塞风险

a、fork子进程,fork这个瞬间一定是会阻塞主线程的(注意,fork时并不会一次性拷贝所有内存数据给子进程,老师文章写的是拷贝所有内存数据给子进程,我个人认为是有歧义的),fork采用操作系统提供的写实复制(Copy On Write)机制,就是为了避免一次性拷贝大量内存数据给子进程造成的长时间阻塞问题,但fork子进程需要拷贝进程必要的数据结构,其中有一项就是拷贝内存页表(虚拟内存和物理内存的映射索引表),这个拷贝过程会消耗大量CPU资源,拷贝完成之前整个进程是会阻塞的,阻塞时间取决于整个实例的内存大小,实例越大,内存页表越大,fork阻塞时间越久。拷贝内存页表完成后,子进程与父进程指向相同的内存地址空间,也就是说此时虽然产生了子进程,但是并没有申请与父进程相同的内存大小。那什么时候父子进程才会真正内存分离呢?“写实复制”顾名思义,就是在写发生时,才真正拷贝内存真正的数据,这个过程中,父进程也可能会产生阻塞的风险,就是下面介绍的场景。

b、fork出的子进程指向与父进程相同的内存地址空间,此时子进程就可以执行AOF重写,把内存中的所有数据写入到AOF文件中。但是此时父进程依旧是会有流量写入的,如果父进程操作的是一个已经存在的key,那么这个时候父进程就会真正拷贝这个key对应的内存数据,申请新的内存空间,这样逐渐地,父子进程内存数据开始分离,父子进程逐渐拥有各自独立的内存空间。因为内存分配是以页为单位进行分配的,默认4k,如果父进程此时操作的是一个bigkey,重新申请大块内存耗时会变长,可能会产阻塞风险。另外,如果操作系统开启了内存大页机制(Huge Page,页面大小2M),那么父进程申请内存时阻塞的概率将会大大提高,所以在Redis机器上需要关闭Huge Page机制。Redis每次fork生成RDB或AOF重写完成后,都可以在Redis log中看到父进程重新申请了多大的内存空间

image-20210411215810191

只能从日志文件中读出指令并将指令按序执行完成,这一过程可能由于数据量可能也会很缓慢,那么是否能够快速的完成数据恢复呢?

2.RDB快照

所谓内存快照(Redis DataBase),就是将redis某一时刻的内存数据生成快照文件,和AOF相比较,RDB记录的是某一时刻的数据,并不是操作,因此数据恢复的会很快

2.1.快照的内容

全量快照:将内存中的所有数据都生成快照

是否会影响主进程呢?

RDB提供两个命令:

save:主进程中执行,会导致阻塞

bgsave:创建一个子进程(fork()),专门用于写入RDB文件,避免了主进程的阻塞(默认选择)

2.2.写时复制技术(Copy-On-Write, COW)

redis是如何做到快照执行期间不影响主进程并允许正常执行读写操作的呢?

简单来说就是bgsave是由主进程fork生成的(AOF的重写机制时的bgrewritraof子进程也是fork生成),可以共享主进程的所有内存数据。bgsave允许后开始读取主进程的内存数据,并把他们写入RDB文件。

针对内存数据,当主进程修改一块数据时,这块数据会被复制一份,生成该数据的副本,然后bgsave把这块数据写入RDB文件,而这个过程中主进程仍然可以修改这块数据,这样就保证了快照的完整性

2.3.增量快照

在全量快照的基础下,如果生成快照的频率太快,会导致如下两个问题:

(1)如果文件太大,贼会导致磁盘压力过大,多个快照竞争有限的磁盘带宽,前一个任务还没执行完,后一个又开始了

(2)fork()bgsave这个过程会堵塞主线程,而且主线程内存越大,阻塞时间越长。

此时我们可以考虑增量快照:

做了一次全量快照后,后续的快照只对修改的数据进行快照记录,这样可以避免每次全量快照的开销,但是增量同步又需要为每条记录新增元数据进行记录,对于内存宝贵的redis而言不太友好

2.4.RDB和AOF混用

Redis4.0提出了混合使用AOF和RDB快照的方式,快照以一定的频率执行,两次快照之间的操作用AOF记录,这个方法既可以数据恢复快速,又能享受到AOF只记命令的简单

img

最后,关于AOF和RDB的选择问题,我想再给你提三点建议:

  • 数据不能丢失时,内存快照和AOF的混合使用是一个很好的选择;
  • 如果允许分钟级别的数据丢失,可以只使用RDB;
  • 如果只用AOF,优先使用everysec的配置选项,因为它在可靠性和性能之间取了一个平衡。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈哈哈张大侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值