0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

MySQL数据库是如何应对故障恢复与数据恢复回滚的问题呢?

马哥Linux运维 来源:稀土掘金 2023-11-27 10:04 次阅读

介绍

今天这篇文章,我想聊一聊MySQL数据库是如何应对故障恢复,与数据恢复回滚的问题。一个最基本的数据库,应当可以做到以下几点:

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

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

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

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

MySQL的架构

关于MySQL的简单架构图。

c6a1b964-8c57-11ee-939d-92fbcf53809c.jpg

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 的操作。从头开始写,写到末尾就又回到开头循环写,如下面这个图所示。

c6b74a54-8c57-11ee-939d-92fbcf53809c.jpg

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 语句时的内部流程。

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

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

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

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

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

c6c5ad10-8c57-11ee-939d-92fbcf53809c.jpg

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

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

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

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

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

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

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

先写 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 的二阶段提交。

链接:https://juejin.cn/post/7304886129774805032







审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • SQL
    SQL
    +关注

    关注

    1

    文章

    738

    浏览量

    43465
  • MYSQL数据库
    +关注

    关注

    0

    文章

    95

    浏览量

    9277

原文标题:探究MySQL的bin log 与 redo log 在数据故障恢复的作用

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    labview有调用mysql数据库问题????

    labview有调用mysql数据库,请问labview打包成exe安装档,怎么把mysql数据库打包进来,是mysql
    发表于 05-19 16:17

    labview连接mysql数据库的问题

    这个ODBC数据流已经成功设置了,为什么用labview连接mysql数据库就出现这个错误?望大神解答,谢谢啦!
    发表于 08-19 08:30

    使用docker安装的mysql5.6实例的恢复方法

    2018-12-23 从aliyun的drs全备恢复数据库到docker的mysql
    发表于 03-14 11:26

    MySQL数据库使用

    关于MySQL数据库的简单操作
    发表于 10-24 14:32

    labview插入数据MySQL数据库

    最近在用labview写入数据MySQL数据库,遇到一个问题:(如图片所示)利用insert指令插入数据,为什么每次插入单个值都会新起一行,而不会自动插入在连续的非空下一行
    发表于 12-26 16:52

    如何在HarmonyOS对数据库进行备份,恢复与加密

    数据库备份与恢复 场景介绍 当应用在处理一项重要的操作,显然是不能被打断的。例如:写入多个表关联的事务。此时,每个表的写入都是单独的,但是表与表之间的事务关联性不能被分割。 如果操作的过程中
    发表于 11-07 08:57

    基于Linux EXT3的MySQL数据库数据恢复

    本文作者是北亚数据恢复中心总工程师张宇, 主要研究服务器及非WINDOWS平台下的数据灾难恢复。 [数据
    发表于 11-03 12:38 0次下载

    NUMA架构下的内存数据库命令日志故障恢复

    NUMA架构下的内存数据库命令日志故障恢复
    发表于 06-24 16:26 26次下载

    数据库数据恢复-oracle数据库常见故障数据恢复分析

    作为存储和处理数据的系统,oracle数据库在使用过程中不可避免会出现各种导致数据丢失和数据损坏的故障。北亚企安
    的头像 发表于 07-27 15:01 449次阅读

    数据库数据恢复-Syabse数据库数据恢复案例

    数据库恢复环境: Sybase版本:SQL Anywhere 8.0。 数据库故障数据库所在的设备意外断电后,
    的头像 发表于 07-28 14:38 658次阅读
    <b class='flag-5'>数据库</b><b class='flag-5'>数据</b><b class='flag-5'>恢复</b>-Syabse<b class='flag-5'>数据库</b><b class='flag-5'>数据</b><b class='flag-5'>恢复</b>案例

    数据库数据恢复-Oracle ASM故障数据恢复案例

    数据库数据恢复环境: Oracle数据库ASM磁盘组有4块成员盘。 数据库故障&分析:
    的头像 发表于 08-11 15:27 884次阅读
    <b class='flag-5'>数据库</b><b class='flag-5'>数据</b><b class='flag-5'>恢复</b>-Oracle ASM<b class='flag-5'>故障</b><b class='flag-5'>数据</b><b class='flag-5'>恢复</b>案例

    数据库数据恢复-oracle数据库报错无法打开的数据恢复案例

    oracle数据库数据恢复环境: 一台服务器,底层由12块硬盘组成一组磁盘阵列,上层操作系统上运行oracle数据库。 oracle数据库
    的头像 发表于 10-12 14:00 495次阅读

    数据库数据恢复MySQL数据库表误删除记录的数据恢复案例

    数据库数据恢复环境: 一台本地windows sever操作系统服务器,服务器上部署mysql数据库单实例,引擎类型为innodb,表内
    的头像 发表于 11-09 15:16 671次阅读
    <b class='flag-5'>数据库</b><b class='flag-5'>数据</b><b class='flag-5'>恢复</b>—<b class='flag-5'>MySQL</b><b class='flag-5'>数据库</b>表误删除记录的<b class='flag-5'>数据</b><b class='flag-5'>恢复</b>案例

    数据库数据恢复—未开启binlog的Mysql数据库数据恢复案例

    mysql数据库数据恢复环境: 本地服务器,windows server操作系统 ,部署有mysql单实例,
    的头像 发表于 12-08 14:18 385次阅读
    <b class='flag-5'>数据库</b><b class='flag-5'>数据</b><b class='flag-5'>恢复</b>—未开启binlog的<b class='flag-5'>Mysql</b><b class='flag-5'>数据库</b><b class='flag-5'>数据</b><b class='flag-5'>恢复</b>案例