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

文章目录

    • 给哪些内存数据做快照?
    • 快照时数据能修改吗?
    • 可以每秒做一次快照吗?
    • 小结
    • 每课一问

更多redis相关知识

上节课,我们学习了 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),那么,这块数据就会被复制一份,生成该数据的副本(键值对 C’)。然后,主线程在这个数据副本上进行修改。同时,bgsave 子进程可以继续把原来的数据(键值对 C)写入 RDB 文件。
!https://s3-us-west-2.amazonaws.com/secure.notion-static.com/ddb8be0d-aac2-446b-bc45-ba757b3d8374/1.png
这既保证了快照的完整性,也允许主线程同时对数据进行修改,避免了对正常业务的影响。
到这里,我们就解决了对“哪些数据做快照”以及“做快照时数据能否修改”这两大问题:Redis 会使用 bgsave 对当前内存中的所有数据做快照,这个操作是子进程在后台完成的,这就允许主线程同时可以修改数据。
现在,我们再来看另一个问题:多久做一次快照?我们在拍照的时候,还有项技术叫“连拍”,可以记录人或物连续多个瞬间的状态。那么,快照也适合“连拍”吗?

可以每秒做一次快照吗?

对于快照来说,所谓“连拍”就是指连续地做快照。这样一来,快照的间隔时间变得很短,即使某一时刻发生宕机了,因为上一时刻快照刚执行,丢失的数据也不会太多。但是,这其中的快照间隔时间就很关键了。
如下图所示,我们先在 T0 时刻做了一次快照,然后又在 T0+t 时刻做了一次快照,在这期间,数据块 5 和 9 被修改了。如果在 t 这段时间内,机器宕机了,那么,只能按照 T0 时刻的快照进行恢复。此时,数据块 5 和 9 的修改值因为没有快照记录,就无法恢复了。
!https://s3-us-west-2.amazonaws.com/secure.notion-static.com/61474440-7276-49de-ab79-8b19978f1893/2.png
所以,要想尽可能恢复数据,t 值就要尽可能小,t 越小,就越像“连拍”。那么,t 值可以小到什么程度呢,比如说是不是可以每秒做一次快照?毕竟,每次快照都是由 bgsave 子进程在后台执行,也不会阻塞主线程。
这种想法其实是错误的。虽然 bgsave 执行时不阻塞主线程,但是,如果频繁地执行全量快照,也会带来两方面的开销。
一方面,频繁将全量数据写入磁盘,会给磁盘带来很大压力,多个快照竞争有限的磁盘带宽,前一个快照还没有做完,后一个又开始做了,容易造成恶性循环。
另一方面,bgsave 子进程需要通过 fork 操作从主线程创建出来。虽然,子进程在创建后不会再阻塞主线程,但是,fork 这个创建过程本身会阻塞主线程,而且主线程的内存越大,阻塞时间越长。如果频繁 fork 出 bgsave 子进程,这就会频繁阻塞主线程了(所以,在 Redis 中如果有一个 bgsave 在运行,就不会再启动第二个 bgsave 子进程)。那么,有什么其他好方法吗?
此时,我们可以做增量快照,所谓增量快照,就是指,做了一次全量快照后,后续的快照只对修改的数据进行快照记录,这样可以避免每次全量快照的开销。
在第一次做完全量快照后,T1 和 T2 时刻如果再做快照,我们只需要将被修改的数据写入快照文件就行。但是,这么做的前提是,我们需要记住哪些数据被修改了。你可不要小瞧这个“记住”功能,它需要我们使用额外的元数据信息去记录哪些数据被修改了,这会带来额外的空间开销问题。如下图所示:
!https://s3-us-west-2.amazonaws.com/secure.notion-static.com/bdcdc43e-fc85-471e-ac3e-5b096e46d3db/3.png
如果我们对每一个键值对的修改,都做个记录,那么,如果有 1 万个被修改的键值对,我们就需要有 1 万条额外的记录。而且,有的时候,键值对非常小,比如只有 32 字节,而记录它被修改的元数据信息,可能就需要 8 字节,这样的画,为了“记住”修改,引入的额外空间开销比较大。这对于内存资源宝贵的 Redis 来说,有些得不偿失。
到这里,你可以发现,虽然跟 AOF 相比,快照的恢复速度快,但是,快照的频率不好把握,如果频率太低,两次快照间一旦宕机,就可能有比较多的数据丢失。如果频率太高,又会产生额外开销,那么,还有什么方法既能利用 RDB 的快速恢复,又能以较小的开销做到尽量少丢数据呢?
Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。简单来说,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。
这样一来,快照不用很频繁地执行,这就避免了频繁 fork 对主线程的影响。而且,AOF 日志也只用记录两次快照间的操作,也就是说,不需要记录所有操作了,因此,就不会出现文件过大的情况了,也可以避免重写开销。
如下图所示,T1 和 T2 时刻的修改,用 AOF 日志记录,等到第二次做全量快照时,就可以清空 AOF 日志,因为此时的修改都已经记录到快照中了,恢复时就不再用日志了。
!https://s3-us-west-2.amazonaws.com/secure.notion-static.com/5cff1961-2b48-4d69-9c9d-ad940c847a32/4.png
这个方法既能享受到 RDB 文件快速恢复的好处,又能享受到 AOF 只记录操作命令的简单优势,颇有点“鱼和熊掌可以兼得”的感觉,建议你在实践中用起来。

小结

这节课,我们学习了 Redis 用于避免数据丢失的内存快照方法。这个方法的优势在于,可以快速恢复数据库,也就是只需要把 RDB 文件直接读入内存,这就避免了 AOF 需要顺序、逐一重新执行操作命令带来的低效性能问题。
不过,内存快照也有它的局限性。它拍的是一张内存的“大合影”,不可避免地会耗时耗力。虽然,Redis 设计了 bgsave 和写时复制方式,尽可能减少了内存快照对正常读写的影响,但是,频繁快照仍然是不太能接受的。而混合使用 RDB 和 AOF,正好可以取两者之长,避两者之短,以较小的性能开销保证数据可靠性和性能。
最后,关于 AOF 和 RDB 的选择问题,我想再给你提三点建议:
数据不能丢失时,内存快照和 AOF 的混合使用是一个很好的选择;
如果允许分钟级别的数据丢失,可以只使用 RDB;
如果只用 AOF,优先使用 everysec 的配置选项,因为它在可靠性和性能之间取了一个平衡。

每课一问

我曾碰到过这么一个场景:我们使用一个 2 核 CPU、4GB 内存、500GB 磁盘的云主机运行 Redis,Redis 数据库的数据量大小差不多是 2GB,我们使用了 RDB 做持久化保证。当时 Redis 的运行负载以修改操作为主,写读比例差不多在 8:2 左右,也就是说,如果有 100 个请求,80 个请求执行的是修改操作。你觉得,在这个场景下,用 RDB 做持久化有什么风险吗?你能帮着一起分析分析吗?
到这里,关于持久化我们就讲完了,这块儿内容是熟练掌握 Redis 的基础,建议你一定好好学习下这两节课。如果你觉得有收获,希望你能帮我分享给更多的人,帮助更多人解决持久化的问题。
到这里,关于持久化我们就讲完了,这块儿内容是熟练掌握 Redis 的基础,建议你一定好好学习下这两节课。如果你觉得有收获,希望你能帮我分享给更多的人,帮助更多人解决持久化的问题。

若有错误与不足请指出,关注DPT一起进步吧!!!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

两分钟解决 :![rejected] master -> master (fetch first) , 无法正常push到远端库

目录 分析问题的原因解决 分析问题的原因 在git push的时候莫名遇到这种情况 若你在git上修改了如README.md的文件。由于本地是没有README.md文件的,所以导致 远端仓库git和本地不同步。 将远端、本地进行合并就可以很好的解决这个问题 注意:直接git pu…

微服务之松耦合

参考:https://microservices.io/post/architecture/2023/03/28/microservice-architecture-essentials-loose-coupling.html There’s actually two different types of coupling: runtime coupling - influences availability design-time coupling - influences…

hot100_240. 搜索二维矩阵 II

hot100_240. 搜索二维矩阵 II 直接遍历列减行增 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性: 每行的元素从左到右升序排列。 每列的元素从上到下升序排列。 示例 1: 输入:matrix [[1,4,7,1…

一步到位Python Django部署,浅谈Python Django框架

Django是一个使用Python开发的Web应用程序框架,它遵循MVC(Model-View-Controller)设计模式,旨在帮助开发人员更快、更轻松地构建和维护高质量的Web应用程序。Django提供了强大的基础设施和工具,以便于处理复杂的业务逻…

Apache PAIMON 学习

参考:Apache PAIMON:实时数据湖技术框架及其实践 数据湖不仅仅是一个存储不同类数据的技术手段,更是提高数据分析效率、支持数据驱动决策、加速AI发展的基础设施。 新一代实时数据湖技术,Apache PAIMON兼容Apache Flink、Spark等…

《计算机网络》课后探研题书面报告_了解PPPoE协议

PPPoE协议的工作原理与应用分析 摘 要 PPPoE(Point-to-Point Protocol over Ethernet)是一种广泛应用于宽带接入的网络协议,特别是在DSL(数字用户线路)和光纤网络中具有重要的应用价值。PPPoE结合了PPP协议的认证、加…

MAC上安装Octave

1. 当前最新版Octave是9.3版本,需要把mac os系统升级到14版本(本人之前的版本是10版本) https://wiki.octave.org/Octave_for_macOS octave的历史版本参考此文档:Octave for macOS (outdated) - Octavehttps://wiki.octave.org/Oc…

mysql-5.7.18保姆级详细安装教程

本文主要讲解如何安装mysql-5.7.18数据库: 将绿色版安装包mysql-5.7.18-winx64解压后目录中内容如下图,该例是安装在D盘根目录。 在mysql安装目录中新建my.ini文件,文件内容及各配置项内容如下图,需要先将配置项【skip-grant-tab…

VSCode连接Github的重重困难及解决方案!

一、背景: 我首先在github创建了一个新的项目,并自动创建了readme文件其次在vscode创建项目并写了两个文件在我想将vscode的项目上传到对应的github上时,错误出现了 二、报错及解决方案: 1.解决方案: 需要在git上配置用…

数据分析:非度量多维排列 NMDS (Non-metric multidimensional scaling)ANOSIM检验分析

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍原理步骤加载R包数据下载导入数据数据预处理计算距离矩阵ANOSIM检验非度量多维排列NMDS应力值(stress value)画图输出系统信息介绍 非度量多维排列(Non-metric Multidimensiona…

Open FPV VTX开源之ardupilot配置

Open FPV VTX开源之ardupilot配置 1. 源由2. 配置3. 总结4. 参考资料5. 补充5.1 飞控固件版本5.2 配置Ardupilot的BF OSD5.3 OSD偏左问题 1. 源由 飞控嵌入式OSD - ardupilot配置使用ardupliot配套OSD图片。 Choose correct font depending on Flight Controller SW. ──>…

硬件实用技巧:TPS54331DR横杠标识识别1引脚

若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/145116969 长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV…

Linux离线部署ELK

文章目录 前期准备开始安装安装elastic search安装logstash安装kibana 配置ELK配置ElasticSearch配置logstash配置kibana 启动ELK启动命令启动测试 设置ELK策略创建ILM策略将ILM策略与日志index关联查看索引是否被ILM策略管理 前期准备 ELK包含三部分软件 ElasticSearch用作搜…

Node.js - Express框架

1. 介绍 Express 是一个基于 Node.js 的 Web 应用程序框架,主要用于快速、简便地构建 Web 应用程序 和 API。它是目前最流行的 Node.js Web 框架之一,具有轻量级、灵活和功能丰富的特点。 核心概念包括路由,中间件,请求与响应&a…

《光学遥感图像中显著目标检测的多内容互补网络》2021-9

一、简介 在本文中,我们提出了一种新的多内容互补网络 (MCCNet) 来探索 RSI-SOD 的多内容互补性。具体来说,MCCNet 基于通用的编码器-解码器架构,并包含一个名为 multi-content complementation module (MC…

【STM8S】STM8S之自定义短、长、连击按键

本文最后修改时间:2018年10月22日 01:57 一、本节简介 本文介绍STM8S系列如何实现按键的短按、长按、连击。 二、实验平台 编译软件:IAR for STM8 1.42.2 硬件平台:stm8s003f3p6开发板 仿真器:ST-LINK 库函数版本&#xff1a…

数据库(MySQL)练习

数据库(MySQL)练习 一、练习1.15练习练习 二、注意事项2.1 第四天 一、练习 1.15练习 win11安装配置MySQL超详细教程: https://baijiahao.baidu.com/s?id1786910666566008458&wfrspider&forpc 准备工作: mysql -uroot -p #以管理…

【深度学习地学应用|滑坡制图、变化检测、多目标域适应、感知学习、深度学习】跨域大尺度遥感影像滑坡制图方法:基于原型引导的领域感知渐进表示学习(一)

【深度学习地学应用|滑坡制图、变化检测、多目标域适应、感知学习、深度学习】跨域大尺度遥感影像滑坡制图方法:基于原型引导的领域感知渐进表示学习(一) 【深度学习地学应用|滑坡制图、变化检测、多目标域适应、感知学习、深度学习】跨域大…

《C++11》并发库:简介与应用

在C11之前,C并没有提供原生的并发支持。开发者通常需要依赖于操作系统的API(如Windows的CreateThread或POSIX的pthread_create)或者第三方库(如Boost.Thread)来创建和管理线程。这些方式存在以下几个问题: …

了解Node.js

Node.js是一个基于V8引擎的JavaScript运行时环境,它允许JavaScript代码在服务器端运行,从而实现后端开发。Node.js的出现,使得前端开发人员可以利用他们已经掌握的JavaScript技能,扩展技能树并成为全栈开发人员。本文将深入浅出地…