百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

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

mhr18 2024-11-28 08:32 18 浏览 0 评论

上节课,我们学习了避免丢失数据的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才能做完。如果在时刻T+5时,一个还没有被写入磁盘的内存数据A,被修改成了A+,那么就会破坏快照的完整性,因为A+不是T时刻的状态。因此,和拍照类似,我们在做快照时也不希望数据”动“,也就是不能被修改。

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

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

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

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

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

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

到这里,我们就解决了对“哪些数据做快照”以及“做快照时数据能是否修改”这两大问题:Redis会使用bgsave对内存中的所有数据做快照,这个操作时子进程在后台完成的,这就允许主线程同时可以修改数据。

现在,我们再来看另一个问题:多久做一次快照?我们在拍照的时候,有一项技术叫“连拍”,可以记录人或物连续多个瞬间状态。那么,快照也适合“连拍”吗?

可以每秒做一次快照吗?

对于快照来说,所谓:“连拍”就是指连续的做快照。这样一来,快照的间隔时间很短,即使某一个时刻发生宕机了,因为上一时刻快照刚执行,丢失的数据也不会太多。但是,这其中的快照间隔时间就很关键了。

如下图所示,我们先在T0时刻做了一次快照,然后又在T0+t时刻做了一次快照,在这期间,数据块5和9被修改了。如果在t这段时间内,机器宕机了,那么,只能按照T0时刻的快照数据进行恢复。此时,数据块5和9的修改值因为没有快照记录,就无法修复了。

所有,想要尽可能的恢复数据,t值就要尽可能的小,t越小,就越像“连拍”。那么,t可以小到什么程度呢,比如说是不是可以每秒做一次快照?毕竟,每次快照都是由bgsave子进程在后台进行,也不会阻塞主线程。

这种想法其实是错误的。虽然bgsave执行时不阻塞主线程,但是,如果频繁的执行全量快照,也会带来两方面的开销。

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

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

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

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

如果我们对每一个键值对的修改,都做个记录,那么,如果有1万个键值对被修改,我们就需要1万条额外的记录。而且,有的时候,键值对非常小,比如只有32字节,而记录它被修改的元数据信息,就可能需要8字节,这样的话,为了”记住“修改,引入的额外空间开销比较大。这对于内存资源宝贵的Redis来说,有些得不偿失。

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

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

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

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

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

小结

这节课,我们学习了Redis用于避免数据丢失的内存快照方法。这个方法的优势在于可以快速恢复数据库,也就是只需要把RDB文件直接读入内存,这就避免了AOF需要顺序,逐一重新执行操作带来的低效性能问题。

不过,内存快照也有它的局限性。它拍的是内存的”大合影“,不可避免的会耗时耗力。虽然,Redis设计了bgsave和写时复制方式,尽可能减少了内存快照对正常读写的影响,但是,频繁快照仍然是不太能接受的。而混合使用RDB和AOF,正好可以取两者之长,避两者之短,以较小的性能开销保证数据的可靠性和性能。

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

数据不能丢失,内存快照和AOF的混合使用是一个很好的选择;

如果允许分钟级别的数据丢失,可以只使用RDB;

如果只用AOF,优先使用everysec的配置选项,因为它在性能和可靠性之间取了一个平衡。

到这里,关于持久化我们就讲完了,这块儿内容是熟练掌握 Redis 的基础,建议你一定好好学习下这两节课。如果你觉得有收获,希望你能帮我分享给更多的人,帮助更多人解决持久化的问题。

如果这篇文章提升了你对Redis的知识,请关注我会持续更新。

相关推荐

【预警通报】关于WebLogic存在远程代码执行高危漏洞的预警通报

近日,Oracle官方发布了2021年1月关键补丁更新公告CPU(CriticalPatchUpdate),共修复了包括CVE-2021-2109(WeblogicServer远程代码执行漏洞)...

医院信息系统突发应急演练记录(医院信息化应急演练)

信息系统突发事件应急预案演练记录演练内容信息系统突发事件应急预案演练参与人员信息科参与科室:全院各部门日期xxxx-xx-xx时间20:00至24:00地点信息科记录:xxx1、...

一文掌握怎么利用Shell+Python实现完美版的多数据源备份程序

简介:在当今数字化时代,无论是企业还是个人,数据的安全性和业务的连续性都是至关重要的。数据一旦丢失,可能会造成无法估量的损失。因此,如何有效地对分布在不同位置的数据进行备份,尤其是异地备份,成为了一个...

docker搭建系统环境(docker搭建centos)

Docker安装(CentOS7)1.卸载旧版Docker#检查已安装版本yumlistinstalled|grepdocker#卸载旧版本yumremove-ydocker.x...

基础篇:数据库 SQL 入门教程(sql数据库入门书籍推荐)

SQL介绍什么是SQLSQL指结构化查询语言,是用于访问和处理数据库的标准的计算机语言。它使我们有能力访问数据库,可与多种数据库程序协同工作,如MSAccess、DB2、Informix、M...

Java21杀手级新特性!3行代码性能翻倍

导语某券商系统用这招,交易延迟从12ms降到0.8ms!本文揭秘Oracle官方未公开的Record模式匹配+虚拟线程深度优化+向量API神操作,代码量直降70%!一、Record模式匹配(代码量↓8...

一文读懂JDK21的虚拟线程(java虚拟线程)

概述JDK21已于2023年9月19日发布,作为Oracle标准Java实现的一个LTS版本发布,发布了15想新特性,其中虚拟线程呼声较高。虚拟线程是JDK21中引入的一项重要特性,它是一种轻量级的...

效率!MacOS下超级好用的Linux虚拟工具:Lima

对于MacOS用户来说,搭建Linux虚拟环境一直是件让人头疼的事。无论是VirtualBox还是商业的VMware,都显得过于笨重且配置复杂。今天,我们要介绍一个轻巧方便的纯命令行Linux虚拟工具...

所谓SaaS(所谓三维目标一般都应包括)

2010年前后,一个科技媒体的主编写一些关于云计算的概念性问题,就可以作为头版头条了。那时候的云计算,更多的还停留在一些概念性的问题上。而基于云计算而生的SaaS更是“养在深闺人未识”,一度成为被IT...

ORA-00600 「25027」 「x」报错(报错0xc0000001)

问题现象:在用到LOB大对象的业务中,进行数据的插入,失败了,在报警文件中报错:ORA-00600:内部错误代码,参数:[25027],[10],[0],[],[],[],[],[...

安卓7源码编译(安卓源码编译环境lunch失败,uname命令找不到)

前面已经下载好源码了,接下来是下载手机对应的二进制驱动执行编译源码命令下载厂商驱动https://developers.google.com/android/drivers?hl=zh-cn搜索NGI...

编译安卓源码(编译安卓源码 电脑配置)

前面已经下载好源码了,接下来是下载手机对应的二进制驱动执行编译源码命令下载厂商驱动https://developers.google.com/android/drivers?hl=zh-cn搜索NGI...

360 Vulcan Team首战告捷 以17.5万美金强势领跑2019“天府杯“

2019年11月16日,由360集团、百度、腾讯、阿里巴巴、清华大学与中科院等多家企业和研究机构在成都联合主办了2019“天府杯”国际网络安全大赛暨2019天府国际网络安全高峰论坛。而开幕当日最激荡人...

Syslog 日志分析与异常检测技巧(syslog发送日志配置)

系统日志包含有助于分析网络设备整体运行状况的重要信息。然而,理解并从中提取有效数据往往颇具挑战。本文将详解从基础命令行工具到专业日志管理软件的全流程分析技巧,助你高效挖掘Syslog日志价值。Gr...

从Oracle演进看数据库技术的发展(从oracle演进看数据库技术的发展的过程)

数据库技术发展本质上是应用需求驱动与基础架构演进的双向奔赴,如何分析其技术发展的脉络和方向?考虑到oracle数据库仍然是这个领域的王者,以其为例,管中窥豹,对其从Oracle8i到23ai版本的核...

取消回复欢迎 发表评论: