作者介绍

王竹峰,去哪儿网数据库专家,擅长数据库开发、数据库管理及维护,一直致力于 MySQL 数据库源码的研究与探索,对数据库原理及实现具有深刻的理解。曾就职于达梦数据库,多年从事数据库内核开发的工作,后转战人人网,任职高级数据库工程师,目前在去哪儿网负责 MySQL 源码研究与运维、数据库管理和自动化运维平台设计开发及实践工作,是 Inception 开源项目及《MySQL 运维内参》的作者,也是 Oracle MySQL ACE。

——

本文作者将出版于《MySQL 运维 内参》中部分内容进行分享,通过多篇文章连载形式,全方位介绍 MySQL 日志实现内幕,可持续关注我们的推文哦!

REDO日志恢复

前面已经很全面地介绍了日志的生成、格式、刷盘、工作原理等,但这些实际上只是数据库运行时的一个“累赘”,没办法才会这样做,因为如果数据库不挂,日志是没有用的,但不挂是不可能的,所以日志是必须要有的。而前面介绍的所有内容都是建立在有日志的前提下,解决如何提高性能,如何保证数据完整性等问题的。那这里将介绍关于日志的新内容,日志的用途之一:数据库恢复。

在第5章中,已经介绍了在 InnoDB 存储引擎的启动过程中,InnoDB 需要做的事情有哪些,具体细节可以参考第 5 章了解。在这一节中,需要重点关注的主要有两个,包括 recv _ recovery _ from _ checkpoint _ start 及 recv _ recovery _ from _ checkpoint _ finish 两个函数的处理(关于两个函数的关系,请参阅第 5 章相关章节)。

InnoDB 启动之前,肯定是处于 shutdown 状态的,而导致 shutdown 的原因只有两种可能性,即正常关闭及 Crash 关闭。这里所说的数据恢复,主要处理的就是针对异常关闭时的情况。当然了,有一个叫 innodb _ fast _ shutdown 的参数,如果设置为 2,也相当于是一次 Crash 了,道理也是一样的。

那可能有人就要问了,如果正常关闭(innodb _ fast _ shutdown 设置为 0 或者 1),那是不是就不执行数据库恢复了?其实不是这样的,不管如何关闭数据库,启动时都会做数据库恢复的操作,只不过正常关闭的情况下,不存在没有做过 checkpoint 的日志,或者说,最新的 checkpoint 已经在最新的 LSN 位置了,又或者说所有的数据页面都已经被刷成了最新的状态。说法可以有多种,但意义其实是一样的。

日志扫描

在开始准备做数据库恢复时,首先要做的就是从日志文件中找到最新的检查点信息。我们已经知道,在日志文件最开始的 4 个页面(每个页面 512 字节)中,存储的是用来管理日志文件及日志写入情况的信息,具体格式可以从前面看到。这里所关注的检查点信息是存储在第1号页面和第3号页面中的,即所谓的 LOG _ CHECKPOINT _ 1 和 LOG _ CHECKPOINT _ 2。在做检查点时,这两个存储位置是轮换着使用的。

基于此,想要找到最新的检查点位置,就需要从上面的两个位置中找到一个最大值,也就是在这个点之前所有的日志都是失效的,并且对应的数据页面都是完整的。而在这个位置之后的页面,有可能是完整的,也有可能需要做 REDO,这个决定于当时 Buffer Pool 的刷盘情况,如果正好有被淘汰出去的页面,那就是完整的,否则还需要通过 REDO 日志来恢复。

先来看一段对应的精简后的代码,如下。

上面的代码,其实就是我们所熟悉的函数 recv _ recovery _ from _ checkpoint _ start_func 的执行过程。归纳起来,其所做的操作包括以下两部分。

从日志文件的固定位置找到最新的检查点信息。

从最新的检查点位置开始扫描日志文件,做数据库恢复。

现在,主要的工作就落在了 recv _ group _ scan _ log _ recs 上面,这个函数所要做的工作,就是将 checkpoint_lsn 位置开始的日志分片处理,每一片为 2MB 大小,对应的精简之后的代码如下。

从上面的函数可以看到,数据库恢复时会根据最新检查点的位置,将日志不断分片读取,然后进行分片处理,这里再来分析一下 InnoDB 是如何做分片处理的。继续看精简之后的代码,如下。

从上面的代码中,可以知道,InnoDB 为了更好地管理日志文件,将连续的日志内容以块为单位来存储,加上头尾信息,继续连续存储,而在使用它的时候,又将这些日志以块为单位读取进来,掐头去尾,拼接在一起,进一步做分析处理。下面就看一下 recv _ parse _ log_recs 是如何做日志分析的。

从上面的代码中可以看出来,InnoDB拿到连续的日志内容之后,以一个 mini-transaction(MTR,物理事务)所包含的日志为单位做分析,再将一个 MTR 中所有的日志记录一个个地分开,存储到 HASH 表中,以便做 APPLY。那么下面再来看加入到 HASH 表中的操作是如何做的。

上面这段代码让我们明白,InnoDB 将每一个日志记录分开之后,存储到了以表空间 ID 及页面号为键值的 HASH 表中。也就是说,相同的页面肯定是存储在一起的,并且在同一个页面上的日志是以先后顺序挂在这个对应的 HASH 节点中的,从而保证了 REDO 操作的有序性。

从这些代码段中可以看到,缓存到 HASH 表之后,应该是可以找合适的时机去 APPLY 了。那什么时候才是合适的时机呢?返回去看到函数 recv _ scan _ log _ recs 的最后调用了函数 recv _ apply _ hashed _ log_recs,那么这就是真正做 APPLY 的函数了。下面详细看一下它的实现。

到这里,应该已经清楚了 REDO 数据库恢复的整个过程,并且可以返回到函数 recv _ recovery _ from _ checkpoint _ start_func 中。看一下最后的说明,做完 REOD 之后,做一次检查点以说明这次数据库恢复已经完成。

各位同学有没有发现这里有一个细节,那就是 InnoDB 在辛辛苦苦将所有日志分析并且根据不同页面通过 HASH 表进行存储之后,特别要注意下面两点特征。

对于同一个页面的 REDO 记录,必然是存储在同一个 HASH 桶中的。

对于某一个页面的所有日志记录,是按照先后顺序来管理的。

这两个特征非常重要,因为 REDO 日志的 APPLY 与顺序有关系,LSN 小的必定要比 LSN 大的先做 APPLY,不然有可能造成数据的覆盖。但是这有一个前提就是同一个页面,不同页面之间是不存在这样的问题的。

那我们想想,是不是只需要保证同一个页面的日志顺序执行其所有的日志记录即可,而不同页面就没必要守这个规则了,答案是肯定的。

目前的 InnoDB 难道不是这样做的吗?在上面的代码中已经看到,它是用了一个两层循环,扫描了整个 HASH 表,慢慢地一条条地做 REDO 恢复。基于上面的分析,其实可以大胆想象一下,REDO 恢复可以实现并行恢复。按照桶的下标为键值分配线程,这样同一个桶必然会分到同一个线程中去做,自然就保证了同一个页面的执行顺序,而不同桶之间的页面是没有关系的,自然就可以并行恢复了。

啊?可以这样?这个想法,可能会让那些把日志文件设置得很大、又经常出现机器宕机问题的同学(上面已经提到了他们)心潮澎湃,这样性能提升得不只一点点了。

还是那句话,这个在需要把日志文件设置很大,并且经常出现宕机时,才会有明显的优化效果。有需求,就能解决,希望这个优化会出现在某个版本中,少一些浪费的时间。

到现在为止,REDO 日志的恢复就做完了。这个时候,才真正体现了这个“累赘”的价值,感谢有你!

上面所讲的,是使用 REDO 日志来恢复数据库的过程,做完之后,整个数据库就是完整的了,保证了所有的数据库表都没有丢数据的情况,所有的数据库页面也已经是完整的了。假设此时对数据库做 DML 操作,也是可以的了。但还有一个问题没有处理,那就是此时的数据库存在脏数据。因为有些事务没有提交,但数据已经存在了(举一个例子,事务在做的过程中,日志已经写完并刷盘,就是没有提交,此时数据库挂了),那根据事务的 ACID 特性,这样的数据就不应该存在,此时,InnoDB 需要做的就是把这些事务回滚掉,这就用到了下面将要讲的“数据库回滚”。

【END】

解读mysql日志_全方位解读 MySQL 日志实现内幕(四)相关推荐

  1. 宝塔清mysql主从日志_宝塔面板Mysql主从日志文件mysql-bin文件清除方法

    今天遇到这个问题,转载一篇不错的文章! 今天发现有台服务器的硬盘满了,这个服务器只放置了一个在线客服软件和10几个MySQL数据库加起来也就几百M的占用,后来查了一遍发现原来是MySQL日志的锅. 发 ...

  2. mysql insert 不需要日志_详解MySQL|你不知道的新特性-8.0错误日志增强

    MySQL 8.0 重新定义了错误日志输出和过滤,改善了原来臃肿并且可读性很差的错误日志. 比如增加了 JSON 输出,在原来的日志后面以序号以及 JSON 后缀的方式展示. 比如我机器上的 MySQ ...

  3. mysql数据库执行事务日志_第十章 MySQL事务及其日志介绍

    一.数据库升级 #1.提出方案 1)升级的方法 2)升级的步骤 3)升级的时间 4)升级步骤可能会出现的问题 5)出现的问题怎么解决,解决时间 6)升级后出现的问题 #2.搭建新的数据库 #3.备份就 ...

  4. 操作 mysql 不生成日志_详解MySQL的日志

    MySQL日志 MySQL的日志记录了MySQL的日常操作和错误信息,通过这些日志我们可以知道MySQL内部发生的事情,可以为MySQL的优化和管理提供必要的信息. MySQL的日志主要有:二进制日志 ...

  5. java 读取mysql日志_如何在MySQL中查看日志文件?

    我已经读过Mysql服务器创建了一个日志文件,它记录了所有活动 - 比如何时执行查询和执行什么查询 . 谁能告诉我我的系统中存在哪些内容?我怎么读呢? 基本上,我需要使用不同的输入备份数据库[两个日期 ...

  6. 删除部分mysql日志_正确删除MYSQl日志方法

    1.查找当 mysql> show binary logs; +------+---–+ | Log_name | File_size | +------+---–+ | mysql-bin.0 ...

  7. mysql下日志_浅谈mysql下日志记录

    1,如何查看mysql执行命令历史 #.mysql_history     此文件记录了在mysql中执行命令的历史 2,事务日志: transaction log:事务型存储引擎自行的管理和使用. ...

  8. Alibaba之MySQL宝典_阿里巴巴内部 MySQL宝典 意外流出!极致经典,堪称数据库的天花板...

    MySQL 是一个关系型数据库,使用 SQL 语言进行增删改查操作,目前属于 Oracle 旗下的产品. MySQL 数据库开源免费,能够跨平台,支持分布式,性能也不错,可以和 PHP.Java 等 ...

  9. mysql猎豹_猎豹网校MySQL数据库

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 猎豹网校MySQL数据库 链接:http://pan.baidu.com/s/1i3wyPjn 密码:qxhm 教程目录 第1章 了解SQL 1.1 数据 ...

最新文章

  1. C#.net Winform获取文件路径
  2. SQL CTE学习总结
  3. MTK:oemlock介绍
  4. printf()详解
  5. python列表写入csv文件_将多个列表写入csv。Python中的文件
  6. 使用hbuilder的maps模块调起百度地图导航
  7. 【To Understand!】LeetCode 117. Populating Next Right Pointers in Each Node II
  8. [剑指Offer] 26.二叉搜索树与双向链表
  9. Java、前端页面中文乱码解决方式
  10. matlab时域频域信号特征提取资料整合
  11. Pano2VR 6 for Mac中文破解版永久激活方法附授权密钥
  12. Visio流程图配色
  13. 05-3. 六度空间 (30)
  14. MTCNN源码详细解读(1)- PNet/RNet/ONet的网络结构和损失函数
  15. 关键元器件选型设计指引--多端口RJ45及网络变压器
  16. Android Studio打包apk详细教程
  17. redis安装(主从)
  18. class和Class的区别
  19. 房建工程项目智慧工地管理系统云平台
  20. 上证50ETF买卖操作详解

热门文章

  1. C++有名管道通信简单示例
  2. ++i和i++哪个效率更高
  3. 条件过滤(商品名称、价格以及商品类别的查询)
  4. 基于SU的快速傅里叶变换(FFT)
  5. PXE-preboot execute environment
  6. Linux内核深入理解定时器和时间管理(5):clockevents 框架
  7. halcon 偏折法_halcon方法学习之blob分析
  8. Python项目实践:天天向上的力量
  9. fiddler修改支付金额_支付漏洞总结
  10. 手机型号大全_双十一高价位华为手机推荐,2020年哪款更值得入手