前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MySQL杂谈系列

MySQL杂谈系列

作者头像
一个无聊的人
发布2022-08-26 09:52:39
1690
发布2022-08-26 09:52:39
举报
文章被收录于专栏:一个无聊的人写的无聊的文章

前言

这是今年3月份整理的一篇博客,在做业务过程中又有了一些新的理解,所以重新进行了梳理,增加了部分示例和绘图,尽管这里分析的是MySQL的binlog 和redo log,但是这里的两段式提交的思想在做支付场景的业务的时候经常用到。

基础知识

在介绍binlog 和redo log之前,先介绍一下MySQL的总体架构,这也是后面学习的基础:

1910240101
1910240101
  1. 连接器:主要负责与客户端(jdbc、bash等)建立链接,验证密码等;
  2. 查询缓存:将查询结果缓存起来,提高查询效率,需要注意的是在MySQL 8.0版本已经彻底取消该模块,因为这里缓存生效的条件比较苛刻,具体原因后台再另起一篇详细分析。
  3. 分析器:如果一次查询没有命中缓存,则需要对操作语句进行语法分析、词法分析(还记得上篇博客讲MySQL编码吗,如果不指定编码这里没办法做词法);
  4. 优化器:索引选择等,目的在于提高语句执行效率;
  5. 执行器:执行语句;
  6. 存储引擎:以插件的形式存在,主流的引擎如上图所示。

日志

分析上图我们发现,MySQL主要分为服务层和存储引擎两大模块,binlog是server层日志,也是MySQL原生支持的日志,而redo log则是InnoDB特有的日志,下面几条结论在网上可以轻易找到,下面我们就针对如下几条进行解读:

  1. 两者都是记录数据的改变,不同的是binlog是记录所有数据的改变信息(无论使用了什么存储引擎),而InnoDB的redo log只是记录使用innodb引擎存储的数据变化。
  2. redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;而binlog是逻辑日志,记录这个语句的原始逻辑;
  3. binlog可以作为恢复数据使用;redo log可以作为异常宕机或者介质故障后的数据恢复使用;
  4. binlog是记录已经提交完毕之后的dml以及ddl sql语句,而innodb redo log是正在执行中的dml以及ddl语句。
分析一

binlog记录的是所有数据的改变,这是因为binlog是MySQL原生支持的,由于最初的时候MySQL是没有InnoDB引擎的,而redo log是InnoDB特有的,所有说binlog记录所有数据的改变信息,而redo log仅支持InnoDB;

分析二

物理日志、逻辑日志,听起来比较抽象,简单说redo log 是经过server层分析优化后的操作,在哪个数据页面做了什么修改的物理记录,binlog 简单认为记录的就是 SQL 语句(实际不仅如此,还记录该语句的反向操作等信息);为了更形象的解释这里,下面放上示例(binlog有多种格式,这只是一种):

1910240102
1910240102

而redo log我没有找到查看文本的方法,redolog不关心执行了什么语句,它只记录在磁盘的哪个位置做了什么修改(实际远不止如此,可查看该篇文章http://mysql.taobao.org/monthly/2017/09/07)。

分析三

首先讲redo log,我们每次执行的语句并不是执行完就写入MySQL,而是先写入到redo log中就算该条语句执行完毕,然后再写入到实际的MySQL存储文件中,其实大多数数据库都是这样的做的,其好处时可以提高执行效率,顺序的写入到一个临时文件,然后批量的更新到存储文件远比直接更新到存储文件效率要高的多。redo log是固定大小的四个文件,每个文件大小可以设置,所以redo log不是持久的,而是循环写入,一个指针记录可写入的开始位置,一个指针记录需要写入存储文件的开始位置。具体如下图所示:

1910240103
1910240103

正是由于redo log的WAL机制,使InnoDB具有crash-safe的能力,即使数据库异常重启也不会导致已提交的数据丢失。

分析四

换种说法,binlog是在一个事务完全提交后才会写入,但是redo log在事务未提交前就会写入,可以简单的理解为实时写入。这里也就引出了另外一个问题,两个日志都记录了一些操作状态,那么两个日志是如何保持一致性的呢?答案是两段式提交。

1910240104
1910240104

我们可以想象这样一个场景,由于机器故障导致丢了一周的数据,值得庆幸的时我们存储了近一周的binlog日志,并且前一周的整库备份也恰好存在,我们可以从整库备份的时间开始取出binlog按照顺序执行到最后一条,那么问题来了,最后一条的状态能否保证redo log和binlog记录的状态是一致的呢。仔细分析发现无论先写binlog还是redo log,如果机器故障恰好在写入binlog和redo log之间,那么两个日志记录的数据库状态都是不一致的。

而两段式提交又是什么情况呢?

1)假设在位置1故障,在恢复到最后一条记录时发现redo log未提交,binlog没有该次操作记录,则放弃恢复,认为最后一次操作未完成;

2)如果在位置2处故障,在恢复到最后一条记录时发现redo未提交,但是binlog存在该次操作,则直接将redo log提交并恢复记录。

这样就保证了binlog和redo log记录的状态永远保持了一致,这种思想实际上在要求一致性的场景下经常被使用。

这里产生另外一个疑问,为什么不能先写redo log再写binlog,如果发现binlog没有该次操作直接不执行不就可以了吗,这样岂不也保证一致了? 这里就涉及到redo log和binlog的设计了,前面已经说过binlog在事务执行完才会写入,而redo log是实时写入的,两段式场景时我们认为redo log提交后就不可回滚事务,因为该次事务已经执行完了,如果再回滚很有可能会覆盖其它事务。假如redo log写入成功,binlog写入失败,MySQL依靠redo log实现crash-safa,这时候发现binlog写入失败,redo log又不能回滚,就会出现不一致的情况。

那为什么不能删除binlog呢而直接使用redo log呢? 因为binlog是持续写入的,而redo log是循环写入的,并不能持续的备份。同理也不能删除redo log而只保留binlog呢,因为binlog的设计之初并不能支持crash-safa。

最后安利一下极客时间《MySQL实战45讲》,作者讲的很细,学完收获很大。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 基础知识
  • 日志
    • 分析一
      • 分析二
        • 分析三
        • 分析四
        相关产品与服务
        云数据库 SQL Server
        腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档