• 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

  • 相关阅读:
    No146.精选前端面试题,享受每天的挑战和学习
    MATLAB程序设计:牛顿迭代法
    面试题——git
    番茄免费小说
    java计算机毕业设计海康物流源码+mysql数据库+系统+lw文档+部署
    驱动挂载物理页代码示例
    JD-怎样获取别人家店铺商品的API接口呢??
    Android 自定义加解密播放音视频(m3u8独立加密)
    微信小程序自定义组件及投票管理与个人中心界面搭建
    2310如何维护旧代码
  • 原文地址:https://blog.csdn.net/ajun_studio/article/details/126035653