MySQL数据库如何应对故障恢复与数据恢复回滚

一个最基本的数据库,应当可以做到以下几点

  • 数据持久化,可以将数据保存到磁盘,服务重启数据依然存在。

  • 可以按照某种关系存储数据,如果你用过IO流,那么你会发现整理数据也是一件复杂的事情。我是该追加写呢还是找到某条数据位置再进行写呢?这是个很复杂的问题。

  • 快速查找。你想想自己如果将数据写入txt,那又如何高效的去找到某条数据?支持随机查找吗?

  • 故障恢复与数据回滚,倘若你的服务断电了,如何确保数据一定是写入到文件的?若是误删或误改了某条数据,你又如何进行恢复?

MySQL的架构

关于MySQL的简单架构图。

图片

MySQL大致可以分为服务层与存储引擎层。在单独抽离了存储引擎层后,你可以选择合适的引擎,例如InnoDb,MyIsam,Memory等等。

关于不同的存储引擎,使用的方式可能不同。我主要想讲的是InnoDb引擎,MySQL 5.5 版本后默认的存储引擎。

MySQL的日志系统

MySQL有三大日志,分别是重做日志(redo log),二进制日志(bin log),以及回滚日志(undo log)。这三个日志非常重要,学习MySQL数据库一定免不了要和他们打交道。

bin log

bin log是Server层的日志,无论使用的是什么引擎,都可以使用这种日志。这个日志记录的是逻辑日志,就是SQL语句。例如insert into table set xx = xx 在bin log中记录的也是这样的一条SQL。而且bin log 采用的是追加写的形式,也即是说在写完一个bin log文件之后,不会覆盖前面的,而是新开一个文件继续追加写。

redo log

redo log 是存储引擎InnoDB所提供的日志模块。个日志记录的是,物理日志。记录的是当前SQL在哪一个数据页上将什么数据修改为了什么数据。

关于redo log,我很喜欢林晓斌老师在《MySQL实战45讲》中讲的例子,酒馆的账本与黑板的例子。在古时候的酒馆中,老板会有一本账本,以及身后的一块黑板。倘若今天有人去喝酒,赊账。在很忙的时候,老板会将这条记录写在黑板上,后续等到酒馆打烊了,不忙的时候,才将这个记录写进自己的账本中。

事实上,在MySQL也是这么做的,如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程 IO 成本、查找成本都很高。

而黑板和账本配合的整个过程,其实就是 MySQL中常说到的 WAL (Write-Ahead Logging)技术,WAL 的全称是 ,它的关键点就是先写日志,再写磁盘,也就是先写黑板,等不忙的时候再写账本。

具体来说,当有一条记录需要更新的时候,InnoDB 引擎就会先把记录写到 redo log(黑板)里面,并更新内存,这个时候更新就算完成了。同时,InnoDB 引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做,这就像酒馆打烊之后老板做的事。

如果今天赊账的不多,掌柜可以等打烊后再整理。但如果某天赊账的特别多,黑板写满了,又怎么办呢?这个时候掌柜只好放下手中的活儿,把粉板中的一部分赊账记录更新到账本中,然后把这些记录从粉板上擦掉,为记新账腾出空间。

与此类似,InnoDB 的 redo log 是固定大小的,比如可以配置为一组 4 个文件,每个文件的大小是 1GB,那么这块“黑板”总共就可以记录 4GB 的操作。从头开始写,写到末尾就又回到开头循环写,如下面这个图所示。

图片

write pos 是当前记录的位置,一边写一边后移。checkpoint 是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。

write pos 和 checkpoint 之间的是“黑板”上还空着的部分,可以用来记录新的操作。如果 write pos 追上 check point,表示“黑板”满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下。

有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为crash-safe。

要理解 crash-safe 这个概念,可以想想我们前面赊账记录的例子。只要赊账记录记在了粉板上或写在了账本上,之后即使掌柜忘记了,比如突然停业几天,恢复生意后依然可以通过账本和粉板上的数据明确赊账账目。

undo log

undo log 记录的是与执行SQL相反的SQL。例如,在user表,id为1的用户age为32,那么执行update table user set age = 45 where id = 1,那么undo log中则会记录update table user set age = 32 where id = 1,如果执行的是delete语句,那么相应的,它会记录一条insert语句。

undo log是MySQL用于事务模块的重要日志,其中的MVCC(多版本并发控制技术)就与undo log版本链强相关。这篇文章重点不在此,因此不再多说。

MySQL如何做数据恢复

假如在今天的12点钟,你误删了一个表。这种情况下该怎么恢复数据?首先,在使用MySQL时,通常会对其进行全量备份。一般是一天、三天或每周一次。

  • 那么此时应当找到最近的一次全量备份放入临时库中。

  • 找到从全量备份的那一刻开始,将bin log重放到误操作今天的12点钟。

  • 如此你便拿到了误操作之前的数据,此时你可以将临时库中的数据按需要恢复回去。

MySQL如何做到故障恢复?(Crash-Safe的能力)

在InnoDB引擎下,MySQL支持事务。因此故障恢复还需要考虑到已提交的数据与未提交的数据。单独靠bin log 或 redo log 是无法保证crash-safe的。

两阶段提交

一条update语句的简单执行过程

我们再来看执行器和 InnoDB 引擎在执行这个简单的 update 语句时的内部流程。

  1. 执行器先找向存储引擎找到 id = 1 这一行。id 作为主键,存储引擎直接用B+树搜索找到这一行。如果id=1 这行所在的数据页已经在内存中,就直接返回给执行器;否则就先从磁盘读入内存中,再返回。

  2. 执行器拿到存储引擎给的行数据,把这个值加上 1,比如原来是 n,现在为 n+1,得到了一行新的数据,再调用存储引擎的接口写入这一行新的数据。

  3. 引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。

  4. 执行器生成这个操作的 binlog,并把 binlog 写入磁盘。

  5. 执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交commit状态。

图片

最后三步看起来有点复杂,InnoDB将 redo log 的写入分为了两个步骤:prepare阶段和commit阶段,这就是两阶段提交

图中白色框表示是在 InnoDB引擎内部执行的,绿色框表示的是在执行器中执行的。

为什么日志需要“两阶段提交”。

由于 redo log 与 bin log 是两个层单独的日志,如果不采用两阶段提交的方式,要么是先写 redo log 再写 bin log,或采用反的顺序。

下面看看这两种方式会出现什么问题。

仍然使用用前面的 update 语句来做例子。假设当前 id=1 的行,字段 a 的值是 0,再假设执行 update 语句过程中在写完第一个日志后,第二个日志还没有写完期间发生了 crash,会出现什么情况呢?

  1. 先写 redo log 后写 binlog。假设在 redo log 写完,binlog 还没有写完的时候,MySQL 进程异常重启。由于我们前面说过的,redo log 写完之后,系统即使崩溃,仍然能够把数据恢复回来,所以恢复后这一行 a 的值是 1。但是由于 binlog 没写完就 crash 了,这时候 binlog 里面就没有记录这个语句。因此,之后备份日志的时候,存起来的 binlog 里面就没有这条语句。然后你会发现,如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 binlog 丢失,这个临时库就会少了这一次更新,恢复出来的这一行 a 的值就是 0,与原库的值不同。

  2. 先写 binlog 后写 redo log。如果在 binlog 写完之后 crash,由于 redo log 还没写,崩溃恢复以后这个事务无效,所以这一行 a 的值是 0。但是 binlog 里面已经记录了 “把 a 从 0 改成 1” 这个日志。所以,在之后用 binlog 来恢复的时候就多了一个事务出来,恢复出来的这一行 a 的值就是 1,与原库的值不同。

可以看到,如果不使用“两阶段提交”,那么数据库的状态就有可能和用它的日志恢复出来的库的状态不一致。

简单说,redo log 和 binlog 都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致。

总结

学习了挺久的MySQL,突然又对其的数据恢复和故障恢复起了兴趣,往深入了解又发现了之前一些之前无法理解的问题突然迎刃而解了。

  • MySQL的数据恢复与故障恢复依赖着几个日志,bin log 与 redo log。bin log 是逻辑日志,记录的是原始SQL语句,redo log 是InnoDB引擎支持的,是物理日志,记录了在哪个数据页修改了哪些数据,并且redo log 是循环写日志。

  • MySQL需要按照一定时间进行全量备份,这样我们可以依靠最近一次全量备份点,以及从该点开始记录的bin log进行数据重放恢复

  • MySQL在使用了InnoDB引擎后,支持了事务,因此故障恢复需要确保可以区分已提交事务与未提交事务。这个依赖于redo log 的二阶段提交。

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

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

相关文章

K 最近邻算法

K 最近邻算法 简单 KNN海伦约会手写数字识别KNN 算法的优缺点 K 最近邻(K-NearestNeighbor,KNN)算法,是 1967 年由 Cover T 和 Hart P 提出的一种用于分类与回归的方法。 基本原理:存在一个带标签的数据集(…

漏电保护器工作原理

漏电保护器 漏电保护器是低压线路中最常用的保护器之一,简称漏保,又称漏电开关或漏电断路器。漏电保护器除了具有空开的所有保护功能外,还具备漏电保护功能。 需要了解 一根通电导线可以产生磁场,磁场与电流方向遵循右手螺旋关…

swingbench造数失败可能原因及解决方法

swingbench造数失败解决方法 1.临时表空间文件内存不足,扩展临时表空间文件内存 alter database tempfile/home/oracle/oradata/orcl/temp01.dbf resize 30G;(这里扩展完temp临时表空间后可以造数成功,则不需要扩展soe用户表空间&#xff09…

【MATLAB】VMD分解+FFT+HHT组合算法

有意向获取代码,请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 VMD(Variational Mode Decomposition)是一种信号分解方法,基于HHT(Hilbert-Huang Transform,希尔伯特-黄变换)。HH…

智能学习台灯_AI摄像头学习机基于MTk8175方案

智能学习台灯是一款专为中小学生设计的学习辅助工具,具有多项突出的参数和功能。首先,它采用了基于联发科MTK平台的解决方案,内置了12纳米四核Cortex-A53处理器,提供了稳定而高效的性能。操作系统方面,智能学习台灯运行…

ATFX汇市:英、日、欧央行行长同日发声,均强调2%通胀目标尚未达成

ATFX动态:11月27日,英国央行行长贝利表示,“我们必须将(通胀)降到2%,这就是为什么我最近一直在给有关我们正在讨论降息或者我们将在可预见的未来降息的假设泼冷水,因为现在谈这个问题还太早”。…

springcloud nacos配置优先级研究及配置管理最佳实践

目录 背景工具版本SpringCloud配置存放位置及相应优先级代码中nacosjar包外挂 多种配置共同存在时的优先级项目配置管理最佳实践无nacos的情况有nacos的情况 参考文献 背景 公司有很多应用是基于SpringBoot/SpringCloud开发。由于在配置文件中经常会涉及数据库账号密码之类的敏…

Boot工程快速启动【Linux】

Boot工程快速启动【Linux】 在idea中打包cd usr/在local文件夹下mkdir app进入app文件夹把打包好的文件(只上传其中的jar)上传到app文件下检查linux中的Java版本,保证和项目的Java 版本保持一致运行 java -jar sp补全***.jar想看效果得查询当…

UniApp项目中 使用微信小程序原生语言 进行开发

看效果 wxcomponents 下放的是微信小程序原生代码写的组件。我进行了封装 上干货 在你下uniApp 项目的根目录创建一个 wxcomponents 名字千万不要错 京东、支付宝灯参考下面图片 官方文档也有介绍 然后在你需要引入原生功能的页面里面引入你的组件(我这里提前已经放…

初识Java 18-2 泛型

目录 构建复杂模型 类型擦除 C中的泛型 迁移的兼容性 类型擦除存在的问题 边界的行为 对类型擦除的补偿 创建类型实例 泛型数组 本笔记参考自: 《On Java 中文版》 构建复杂模型 泛型的一个优点就是,能够简单且安全地创建复杂模型。 【例子&am…

nginx反向代理解决跨域前端实践

需求实现 本地请求百度的一个搜索接口,用nginx代理解决跨域思路:前端和后端都用nginx代理到同一个地址8080,这样访问接口就不存在跨域限制 本地页面 查询一个百度搜索接口,运行在http://localhost:8035 index.js const path …

elment Loading 加载组件动态变更 text 值bug记录

先上效果图: 倒计时4分钟组件方法 // 倒计时 4分钟getSencond() {this.countDown 4分00秒this.interval setInterval(() > {this.maxTime--;let minutes Math.floor(this.maxTime / 60);let seconds Math.floor(this.maxTime % 60);minutes minutes < 10 ? 0 minu…

台式机加独显引发的故事

弄到一块NVIDIA1660显卡&#xff0c;想要加到台式机&#xff0c;枯树逢春&#xff1b;中间引发不少事情&#xff0c;记录下来共勉 1.台式机插入显卡 1&#xff09;拆开主机后部的接口片 2&#xff09;显卡插入显卡巢&#xff0c;很内存条结构类似&#xff08;长短布局&#xff…

电子学会C/C++编程等级考试2022年06月(二级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:小白鼠再排队 N只小白鼠(1 < N < 100),每只鼠头上戴着一顶有颜色的帽子。现在称出每只白鼠的重量,要求按照白鼠重量从小到大的顺序输出它们头上帽子的颜色。帽子的颜色用 “red”,“blue”等字符串来表示。不同的小白…

React 之 airbnb - 项目实战

一、开发前言 1. 规范 2. 创建项目 node -v > 18.0.0 npm -v > 8.6.0 create-react-app star-airbnb 3. 项目基本配置 配置jsconfig.json {"compilerOptions": {"target": "es5","module": "esnext","ba…

kafka2.x常用命令:创建topic,查看topic列表、分区、副本详情,删除topic,测试topic发送与消费

原创/朱季谦 接触kafka开发已经两年多&#xff0c;也看过关于kafka的一些书&#xff0c;但一直没有怎么对它做总结&#xff0c;借着最近正好在看《Apache Kafka实战》一书&#xff0c;同时自己又搭建了三台kafka服务器&#xff0c;正好可以做一些总结记录。 本文主要是记录如…

Spring --- 创建一个Spring项目

文章目录 创建一个Maven项目添加Spring框架支持添加启动类 创建一个Maven项目 注&#xff1a;我们需要使用 Maven 来管理依赖&#xff0c;所以需要创建一个Maven项目 添加Spring框架支持 注&#xff1a; 添加这两个依赖才能正确使用 Spring在添加依赖后记得刷新&#xff0c;把依…

【Nginx篇】Nginx轻松上手

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Unity2D-URP基于ShaderGraph创建带粒子特效的激光光束

文章目录 创建Shader新建Node: UV新建Node: Split......参数说明 基于Shader创建Material创建Line创建粒子系统StartVFX创建粒子材质更改粒子系统的材质设置透明模式设置粒子效果创建一个Beam设置EndVFX效果预览激光光束管理脚本最终预览 创建Shader Create --> Shader Gra…

零信任、SASE还在因不标准的身份系统难对接而无法发挥真正力量?这份标准化的解决方案助您一臂之力

身份安全是网络安全的一个重要领域&#xff0c;旨在确保用户的身份安全可信&#xff0c;防止未经授权的访问和数据泄漏等问题。目前主流的信息安全趋势强调可持续验证、多源信任评估、动态防护、可持续数据防护、一体化安全审计等&#xff0c;特别是零信任、SASE等技术均以身份…