内存快照:宕机后,Redis如何实现快速恢复?RDB

AOF的回顾

         回顾Redis 的AOF的持久化机制。 Redis 避免数据丢失的 AOF 方法。这个方法的好处,是每次执行只需要记录操作命令,需要持久化的数据量不大。一般而言,只要你采用的不是 always 的持久化策略,就不会对性能造成太大影响。

        但是,也正因为记录的是操作命令,而不是实际的数据,所以,用 AOF 方法进行故障恢复
的时候,需要逐一把操作日志都执行一遍。如果操作日志非常多,Redis 就会恢复得很缓
慢,影响到正常使用。那这就引出了这篇文章所写的:内存快照。所谓内存快照,就是指内存中的数据在某一个时刻的状态记录。

        对 Redis 来说,它实现类似照片记录效果的方式,就是把某一时刻的状态以文件的形式写
到磁盘上,也就是快照。这样一来,即使宕机,快照文件也不会丢失,数据的可靠性也就
得到了保证。这个快照文件就称为 RDB 文件,其中,RDB 就是 Redis DataBase 的缩
写。

        和 AOF 相比,RDB 记录的是某一时刻的数据,并不是操作,这样恢复数据会很快,那为啥不直接把RDB作为最优选呢?

        我们需要考虑两件事情:

        对哪些数据做快照?这关系到快照的执行效率问题;
        做快照时,数据还能被增删改吗?这关系到 Redis 是否被阻塞,能否同时正常处理请求。

给哪些内存数据做快照?

        Redis 的数据都在内存中,为了提供所有数据的可靠性保证,它执行的是全量快照,也就
是说,把内存中的所有数据都记录到磁盘中,这就类似于给 100 个人拍合影,把每一个人
都拍进照片里。这样做的好处是,一次性记录了所有数据,一个都不少。

        当你给一个人拍照时,只用协调一个人就够了,但是,拍 100 人的大合影,却需要协调
100 个人的位置、状态,等等,这当然会更费时费力。同样,给内存的全量数据做快照,
把它们全部写入磁盘也会花费很多时间。而且,全量数据越多,RDB 文件就越大,往磁盘
上写数据的时间开销就越大。

        对于 Redis 而言,它的单线程模型就决定了,我们要尽量避免所有会阻塞主线程的操作,
所以,针对任何操作,我们都会提一个灵魂之问:“它会阻塞主线程吗?”RDB 文件的生成
是否会阻塞主线程,这就关系到是否会降低 Redis 的性能。

        Redis 提供了两个命令来生成 RDB 文件,分别是 save 和 bgsave

        save:在主线程中执行,会导致阻塞;
        bgsave:创建一个子进程,专门用于写入 RDB 文件,避免了主线程的阻塞,这也是
        Redis RDB 文件生成的默认配置。

好了,这个时候,我们就可以通过 bgsave 命令来执行全量快照,这既提供了数据的可靠
性保证,也避免了对 Redis 的性能影响。

接下来,我们要关注的问题就是,在对内存数据做快照时,这些数据还能“动”吗? 也就是
说,这些数据还能被修改吗? 这个问题非常重要,这是因为,如果数据能被修改,那就意
味着 Redis 还能正常处理写操作。否则,所有写操作都得等到快照完了才能执行,性能一
下子就降低了。

快照时数据能修改吗?

在给别人拍照时,一旦对方动了,那么这张照片就拍糊了,我们就需要重拍,所以我们当
然希望对方保持不动。对于内存快照而言,我们也不希望数据“动”。

举个例子。我们在时刻 t 给内存做快照,假设内存数据量是 4GB,磁盘的写入带宽是
0.2GB/s,简单来说,至少需要 20s(4/0.2 = 20)才能做完。如果在时刻 t+5s 时,一个
还没有被写入磁盘的内存数据 A,被修改成了 A’,那么就会破坏快照的完整性,因为
A’不是时刻 t 时的状态。因此,和拍照类似,我们在做快照时也不希望数据“动”,也就
是不能被修改。

但是,如果快照执行期间数据不能被修改,是会有潜在问题的。对于刚刚的例子来说,在
做快照的 20s 时间里,如果这 4GB 的数据都不能被修改,Redis 就不能处理对这些数据的
写操作,那无疑就会给业务服务造成巨大的影响。

你可能会想到,可以用 bgsave 避免阻塞啊。这里我就要说到一个常见的误区了,避免阻
塞和正常处理写操作并不是一回事。此时,主线程的确没有阻塞,可以正常接收请求,但
是,为了保证快照完整性,它只能处理读操作,因为不能修改正在执行快照的数据。

为了快照而暂停写操作,肯定是不能接受的。所以这个时候,Redis 就会借助操作系统提
供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,正常处理写操作。

简单来说,bgsave 子进程是由主线程 fork 生成的,可以共享主线程的所有内存数据。
bgsave 子进程运行后,开始读取主线程的内存数据,并把它们写入 RDB 文件。

此时,如果主线程对这些数据也都是读操作(例如图中的键值对 A),那么,主线程和
bgsave 子进程相互不影响。但是,如果主线程要修改一块数据(例如图中的键值对 C),
那么,这块数据就会被复制一份,生成该数据的副本。然后,bgsave 子进程会把这个副本
数据写入 RDB 文件,而在这个过程中,主线程仍然可以直接修改原来的数据。

 这既保证了快照的完整性,也允许主线程同时对数据进行修改,避免了对正常业务的影
响。

到这里,我们就解决了对“哪些数据做快照”以及“做快照时数据能否修改”这两大问
题:Redis 会使用 bgsave 对当前内存中的所有数据做快照,这个操作是子进程在后台完
成的,这就允许主线程同时可以修改数据。
现在,我们再来看另一个问题:多久做一次快照?我们在拍照的时候,还有项技术叫“连
拍”,可以记录人或物连续多个瞬间的状态。那么,快照也适合“连拍”吗?

可以每秒做一次快照吗?

连拍的间隔比较大的话就是你当及两次拍照的之间发生宕机的话,丢失的数据就会很多。

但是如果连拍间隔非常小的话,虽然 bgsave 执行时不阻塞主线程,但是,如果频繁地执行全量
快照,也会带来两方面的开销。:

一方面,频繁将全量数据写入磁盘,会给磁盘带来很大压力,多个快照竞争有限的磁盘带
宽,前一个快照还没有做完,后一个又开始做了,容易造成恶性循环。

另一方面,bgsave 子进程需要通过 fork 操作从主线程创建出来。虽然,子进程在创建后
不会再阻塞主线程,但是,fork 这个创建过程本身会阻塞主线程,而且主线程的内存越
大,阻塞时间越长。如果频繁 fork 出 bgsave 子进程,这就会频繁阻塞主线程了。那么,
有什么其他好方法吗?

此时,我们可以做增量快照,所谓增量快照,就是指,做了一次全量快照后,后续的快照
只对修改的数据进行快照记录,这样可以避免每次全量快照的开销

在第一次做完全量快照后,T1 和 T2 时刻如果再做快照,我们只需要将被修改的数据写入
快照文件就行。但是,这么做的前提是,我们需要记住哪些数据被修改了。你可不要小瞧
这个“记住”功能,它需要我们使用额外的元数据信息去记录哪些数据被修改了,这会带
来额外的空间开销问题。如下图所示:

 但是我们两次拍照之间有1万键值对别更改了。但是存出这个增量的空间很有效。所以这个增量的只适用于修改次数少的。

到这里,你可以发现,虽然跟 AOF 相比,快照的恢复速度快,但是,快照的频率不好把
握,如果频率太低,两次快照间一旦宕机,就可能有比较多的数据丢失。如果频率太高,
又会产生额外开销,那么,还有什么方法既能利用 RDB 的快速恢复,又能以较小的开销做
到尽量少丢数据呢

AOF和RDB混合使用

Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。简单来说,内存快照以一
定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。

这样一来,快照不用很频繁地执行,这就避免了频繁 fork 对主线程的影响。而且,AOF
日志也只用记录两次快照间的操作,也就是说,不需要记录所有操作了,因此,就不会出
现文件过大的情况了,也可以避免重写开销。

如下图所示,T1 和 T2 时刻的修改,用 AOF 日志记录,等到第二次做全量快照时,就可
以清空 AOF 日志,因为此时的修改都已经记录到快照中了,恢复时就不再用日志了。

 这个方法既能享受到 RDB 文件快速恢复的好处,又能享受到 AOF 只记录操作命令的简单
优势,颇有点“鱼和熊掌可以兼得”的感觉。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/62421.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Godot 4 源码分析 - 碰撞

碰撞功能应该是一个核心功能,它能自动产生相应的数据,比如目标对象进入、离开本对象的检测区域。 基于属性设置,能碰撞的都具备这样的属性:Layer、Mask. 在Godot 4中,Collision属性中的Layer和Mask属性是用于定义碰撞…

任务12、Quality指令加持,Midjourney生成电影级数码作品

12.1 任务概述 本次实验任务旨在帮助你掌握Midjourney AI绘画中的Quality指令。通过深入介绍Quality指令的概念和作用,我们将解释为什么它在绘画中至关重要。通过测试不同的Quality参数对绘画效果的影响,并提供实战演示,你将学会如何在Midjourney中设置Quality参数以达到更…

使用uni-app的uniCloud 云数据库入门:实现一个简单的增删改查

官方云数据库文档 前置步骤使用uni-app新建一个uniCloud项目 [外链图片转存失败,源站可能有防盗官方云数据库文档]!链机制,建议将()https://uniapp.dcloud.net.cn/uniCloud/hellodb.html)] 新建表 这里我加了几个测试字段 createTime、remark、money // 文档教程: https://un…

利用appium抓取app中的信息

一、appium简介 二、appium环境安装 三、联调测试环境 四、利用appium自动控制移动设备并提取数据

GO学习之 网络通信(Net/Http)

GO系列 1、GO学习之Hello World 2、GO学习之入门语法 3、GO学习之切片操作 4、GO学习之 Map 操作 5、GO学习之 结构体 操作 6、GO学习之 通道(Channel) 7、GO学习之 多线程(goroutine) 8、GO学习之 函数(Function) 9、GO学习之 接口(Interface) 10、 文章目录 GO系列前言一、H…

计算机网络体系结构

计算机网络体系结构 常用的网络体系结构 OSI体系结构 为了使不同体系结构的计算机网络都能互连,国际标准化组织于1977年成立了专门机构研究该问题,不就他们就提出了一个试图使各种计算机在世界范围内互连成网的标准框架,也就是著名的开放系…

docker部署jenkins且jenkins中使用docker去部署项目

docker部署jenkins且jenkins中使用docker去部署项目 1、确定版本 2.346.1是最后一个支持jdk8的 2、编写docker-compose.yml并执行 在这个目录中新增data文件夹,注意data是用来跟docker中的文件进行映射的 docker-compose.yml version: "3.1" service…

Java私有仓库Nexus搭建部署

Java私有仓库Nexus搭建部署 需求分析 为什么要搭建部署Nexus私有仓库,有什么用,用来干什么,怎么用,也许是大家看到这篇文章的第一个反应和疑惑,这里给大家先笼统的做一个介绍: 依赖管理:在Java…

USB采集卡如何打pts

一、使用采集卡提供的pts 二、手动打pts 1.usb采集设备pts的问题 2.采集卡驱动,UVC/UAC,ffmpeg的关系 3.如何自己打pts 4.音视频同步调优 5.NTP等联网调时工具带来的不同步问题 一、使用采集卡提供的pts 我们用使用pc摄像头和使用pc麦克风声卡里的方法&…

idea数据库快速上手-库操作与表结构和数据操作

引言 对数据库的操作无非就是执行SQL语句,要想熟练操作数据库,就要熟练运用SQL语句。 一,数据库操作 展示当前服务器内的数据库 -- 展示服务器内的数据库 show databases; show schemas; 执行结果: 创建数据库: --…

【福建事业单位-推理判断】07逻辑论证-削弱

【福建事业单位-推理判断】07逻辑论证-削弱-加强 题型分析一、削弱题1.1 否定论点1.2 拆桥(话题不一致)1.3否定论据(否定强度低于前面两者)1.4 因果关系(论点中的因果关系)——力度相当于否定论点1.5 另有他…

docker search 镜像报错: connect: no route to host (桥接模式配置静态IP)

如下 原因 可能有多种: ① 没有开放防火墙端口 ② ip地址配置有误 解决 我是因为虚拟机采用了桥接模式,配置静态ip地址有问题。 先确认虚拟机采用的是 桥接模式,然后启动虚拟机。 1、打开命令行,输入下面指令,打开…

Docker 快速安装 MinIO

概述 MinIO 是一款基于Go语言的高性能对象存储服务,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等。 拉取docker镜像 docker pull minio/minio创建宿主机数据目录(共享数据卷) 此…

FPGA----UltraScale+系列的PS侧与PL侧通过AXI-HP交互(全网唯一最详)附带AXI4协议校验IP使用方法

1、之前写过一篇关于ZYNQ系列通用的PS侧与PL侧通过AXI-HP通道的文档,下面是链接。 FPGA----ZCU106基于axi-hp通道的pl与ps数据交互(全网唯一最详)_zcu106调试_发光的沙子的博客-CSDN博客大家好,今天给大家带来的内容是&#xff0…

Java根据坐标经纬度计算两点距离(5种方法)、校验经纬度是否在圆/多边形区域内的算法推荐

目录 前言 一、根据坐标经纬度计算两点距离(5种方法) 1.方法一 2.方法二 3.方法三 4.方法四 5.方法五 5.1 POM引入第三方依赖 5.2 代码 6.测试结果对比 二、校验经纬度是否在制定区域内 1.判断一个坐标是否在圆形区域内 2.判断一个坐标是否…

回归预测 | MATLAB实现基于SVM-RFE-BP支持向量机递归特征消除特征选择算法结合BP神经网络的多输入单输出回归预测

回归预测 | MATLAB实现基于SVM-RFE-BP支持向量机递归特征消除特征选择算法结合BP神经网络的多输入单输出回归预测 目录 回归预测 | MATLAB实现基于SVM-RFE-BP支持向量机递归特征消除特征选择算法结合BP神经网络的多输入单输出回归预测预测效果基本介绍研究内容程序设计参考资料…

C语言代码的x86-64汇编指令分析过程记录

先通过Xcode创建一个terminal APP&#xff0c;语言选择C。代码如下&#xff1a; #include <stdio.h>int main(int argc, const char * argv[]) {int a[7]{1,2,3,4,5,6,7};int *ptr (int*)(&a1);printf("%d\n",*(ptr));return 0; } 在return 0处打上断点&…

数据库设计范式

数据库的设计范式都包括哪些 我们在设计关系型数据库模型的时候&#xff0c;需要对关系内部各个属性之间联系的合理化程度进行定义&#xff0c;这就有了不同等级的规范要求&#xff0c;这些规范要求被称为范式&#xff08;NF&#xff09;。你可以把范式理解为&#xff0c;一张数…

【【萌新的STM32 学习-6】】

萌新的STM32 学习-6 BSP 文件夹&#xff0c;用于存放正点原子提供的板级支持包驱动代码&#xff0c;如&#xff1a;LED、蜂鸣器、按键等。 本章我们暂时用不到该文件夹&#xff0c;不过可以先建好备用。 CMSIS 文件夹&#xff0c;用于存放 CMSIS 底层代码&#xff08;ARM 和 ST…

ESP32(MicroPython)四轮差速底盘遥控

本项目主控改为ESP32-C3&#xff0c;沿用之前的L298N电机驱动、12.6v 18650电池组、LM7805降压模块的方案。电机改用1&#xff1a;19减速比的&#xff0c;使用130mm车轮&#xff0c;主要考虑越野用途。 遥控方面&#xff0c;本项目使用HC-14模块&#xff0c;实测连接到电脑可以…