05-Redis 持久化之RDB 的奥秘

大家好,我是飓风。

上一篇中,Redis 持久化AOF你真的了解吗?,我们聊了AOF,我们知道AOF记录了所有执行的命令,体积较大,恢复的时候需要逐条执行进行恢复,恢复速度会比较慢,那有没有体积小,恢复速度很快的方式呢?用过的redis的人,我想大多数人都是知道RDB的,那么今天就来说说Redis RDB的持久化。

什么是RDB

RDB 是Redis DataBase 的缩写。

RDB 中文我们称之为内存快照【RDB 文件是经过压缩的二进制文件,占用空间很小】,也就是记录redis某一时刻的内存中的全部数据,将这个时刻的数据持久化到磁盘,实际有多少数据就存储多少,而不是像AOF那样,同样的key,操作多次,会有多条记录,都会持久化到AOF中。

所以要时刻记住,RDB 记录的是某一时刻的内存数据,不是操作的记录,所以在恢复的时候,直接加载数据到内存,而不是执行操作记录恢复,所以恢复速度会很快。

RDB 文件的生成

好了,了解完RDB 的概念之后,RDB文件是怎么生成的呢?

redis 给我们提供了两个命令用于生成RDB文件。

  • save:阻塞redis 主线程。
  • bgsave: 执行过程不会阻塞redis主线程。

大多数情况都会配置走bgsave 来生成RDB文件,由于save命令会阻塞redis主线程,会操作redis不能处理其他读写请求,这个业务肯定是不能容忍的。而bgsave并不会阻塞【这里不会阻塞说的是生成RDB不会阻塞】,bgsave这里我们需要详细的说明。

过程如下:

  • 执行bgsave命令 。
  • redis 主线程会fork 出 bgsave 子进程。
  • bgsave子进程 会读取redis 的内存数据,生成RDB 文件。

这里有些细节需要重点说下,是怎么读取内存数据的呢?

fork子进程 会阻塞redis 主线程,因为fork过程copy 当时redis 内存的内存页表给子进程,如果redis 内存很大,那么页表的就很大,那么copy 的过程就会增加时间,那么copy这段时间内,redis 是不能处理新来的请求,那么redis的延迟就会增加了,阻塞了redis 主线程的读写操作。

copy完成内存页表之后,那么此时子进程和redis 主线程(或者叫主进程)的内存页面都指向了同一块内存地址,子进程bgsave就可以读取内存数据,开始生成RDB文件了。

因为RDB是redis 某一时刻的全部内存快照,那么如果在生成RDB文件的过程中,如果新的请求过来,修改了某个key,那么这个内存快照是不是就会被破坏掉了呢?

这里是不会破坏掉的,这里redis 用到的linux 的写时复制技术(CopyOnWrite,缩写COW),当有一个写操作过来的时候,如果此时这个key存在,那么会复制这个key所在的内存页到一块新的地址,然后再接着修改内容,如果内存页很大,那么当时的这个写操作就会很慢,增大延迟,所以redis 所在的机器不要开启大页机制。由于redis这里利用COW技术,既不会阻塞新的请求的处理,也不会破坏当时的内存快照了。

具体看图说话:

bgsave 在进行fork子进程的过程。

左侧为redis主线程的内存页面,fork的过程需要copy给子进程一份,然后父子进程都指向了相同的内存地址,也就是都指向了黄色内存区域内的蓝色长方形,蓝色长方形可以理解为内存页。

在这里插入图片描述

当发生了key的修改会发生了什么,继续看图说话:

在这里插入图片描述

这个是修改了C,那么就会copy C 所在的内存页到一个新的地址,接着修改C的内容,此时主线程的内存页面也会指向到新的内存地址。注意看图里的箭头也发生了变化。【子进程箭头或者说映射关系会保持不变】。

如果在RDB生成过程中,有大量的修改操作,可能会造成内存不足,因为会copy大量的内存页,最坏的情况会增加为原来内存的2倍。

缺点

说了RDB生成的过程,那么RDB 有什么缺点呢? 缺点我想大家肯定都已经清楚了,就是RDB 保存的是某一时刻的内存全部数据,假如我们是在t时刻生成RDB 文件,那么生成的时间是5s,那么在t之后的这段5s 内的内存数据,是不能进行保存的,那么就会丢失掉。所以你一定要合理配置生成RDB的频率。

其实在reids 4 之后,redis 还提供了AOF 和RDB 混合使用的方式,就是在每次生成RDB之间增加AOF,这样AOF的文件也不会很大,同时也弥补了每次生成RDB之间会丢失数据的缺点。

混合持久化本质是通过 AOF 后台重写(bgrewriteaof 命令)完成的,不同的是当开启混合持久化时,fork 出的子进程先将当前全量数据以 RDB 方式写入新的 AOF 文件,然后再将 AOF 重写缓冲区(aof_rewrite_buf_blocks)的增量命令以 AOF 方式写入到文件,写入完成后通知主进程将新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件。

开启:混合持久化的配置参数为 aof-use-rdb-preamble,配置为 yes 时开启混合持久化,在 redis 4 刚引入时,默认是关闭混合持久化的,但是在 redis 5 中默认已经打开了。
关闭:使用 aof-use-rdb-preamble no 配置即可关闭混合持久化。

优点:结合 RDB 和 AOF 的优点, 更快的重写和恢复。
缺点:AOF 文件里面的 RDB 部分不再是 AOF 格式,可读性差。

总结

什么是RDB?

RDB 文件是是经过压缩的二进制文件,占用空间很小,redis某一时刻的全部内存数据。

RDB的生成过程

这里需要注意fork子进程bgsave 都干了什么,
1 生成fork 子进程
fork过程是会阻塞主线程的,因为会copy 内存页面,内存越大,页面就越大,那么copy 就会很慢,延迟就会增加。
2 生成之后,子进程和父进程页表都指向了相同的内存地址,此时开始读取内存,生成RDB。

RDB缺点

RDB 在服务器故障时容易造成数据的丢失,因为存储的是某一时刻的数据。
当内存很大的时候,页表就很大,页面的拷贝会让fork过程很慢。
如果存在修改key的操作,那么COW会涉及到内存页的拷贝,如果开启大页机制,那么拷贝就会变慢,增加主线程的延迟,redis 不要开启大页机制。
COW技术可能会造成内存扩张为原来的两倍,造成内存不足。


今天的分享就到这里了,码字画图不易,期待你的点赞、关注、转发,谢谢。

你的点赞、关注 是飓风创作的最大动力。

如有问题 欢迎人才请留言,一起讨论和勘误。

欢迎关注 github

微信添加: zookeeper0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

飓风zj

感谢打赏,thanks

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

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

打赏作者

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

抵扣说明:

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

余额充值