MySQL update执行流程到 redo log深入理解

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
日志服务 SLS,月写入数据量 50GB 1个月
简介: MySQL update执行流程到 redo log深入理解

前面我们分析过一个查询语句的执行流程,并且解释了执行过程中涉及的模块。一条查询语句一般是经过连接器、分析器、优化器、执行器等功能模块,最后到达存储引擎。老铁们可以点击链接 查询语句在 MySQL 如何执行 学习上篇内容。

这次,我们来深入学习一条更新语句在 MySQL 中的执行流程。通过此文我们可以充分了解 什么是 Redo Log

表结构创建

首先我们先创建一张表,只有主键 ID,以及 int 类型字段 c。

create table T(ID int primary key, c int);

现在我们要更新一条数据,语句如下:

update T set c=c+1 where ID=2;

更新语句其实也跟查询语句的流程类似,只不过多了 redo log、undo log 以及 binlog 日志。

上一篇查询语句的执行流程我们说过,在一个表上有更新的时候,跟这个表有关的查询缓存会失效,所以这条语句会把整个 T 表的缓存结果都清空。这也是为何我们不建议使用查询缓存的原因。

账本与记账板

假如您当了小超市老板,自然会有一个账本记录交易记录,但是可能还要一个赊账记录。因为村里有个姑娘叫小芳,长得美丽又善良。有时候会到你这里白嫖,额,不是,是赊账。你先把记录写在小粉板上,等夜深人静的时候就把粉板的数据同步到归档的账本中。当然粉板也有满的时候,所以当粉板满了就要对账写入账本中,

所以,如果有人要来赊账,或者还账的时候,通常有两种做法:

  1. 直接把账本翻出来,把这次的赊账加上去或者扣除。
  2. 先在粉板上记下这次的帐,等打烊后再把账本翻出来核算。

在生意忙的时候,我们肯定选择后者,因为前者操作太麻烦了。首先,你得找到这个人的赊账总额那条记录。你想想,密密麻麻几十页,掌柜要找到那个名字,可

能还得带上老花镜慢慢找,找到之后再拿出算盘计算,最后再将结果写回到账本上。这个时候小芳来赊账,等半天。以后还怎么约小芳到小树林呢?

MySQL 中也有这个问题,如果每一次操作都要写进磁盘,然后磁盘也要找到对应的记录,然后再更新。整个过程的 IO 成本,查询成本都很高,为了解决这个问题,MySQL的设计者就用了类似小超市老板粉板的思路来提升更新效率。

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

redo log

首先我们要明确的是binlog 日志是在 server 层的,而redo logInnoDB 特有的。

当有一条记录需要更新的时候,InnoDB引擎就会先把记录写到 redo log(粉板)中,并更新内存,这个时候就算完成了。同时 引擎会在适当的时候将这个记录更新到磁盘里,而更新往往是系统比较闲的时候,这就是打样以后掌柜做的事情。

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

write pos 是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头。checkpoint 是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。

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

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

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

binlog

MySQL 的整体架构其实有两块:一块是 Server 层,还有一块是 引擎层,负责存储相关。前面我们提到的 redo logInnoDB 引擎持有的,而 Server 层也有自己的日志,叫 binlog(归档日志)。

那为何会有两份日志呢?

因为最开始 MySQL 里并没有 InnoDB 引擎。MySQL 自带的引擎是 MyISAM,但是

MyISAM 没有 crash-safe 的能力(因为是 Server 层与引擎层是两个独立的模块),binlog 日志只能用于归档。而 InnoDB 是另一个公司以插件形式引入 MySQL 的,既然只依靠 binlog 是没有 crash-safe 能力的,所以 InnoDB 使用另外一套日志系统——也就是 redo log 来实现 crash-safe 能力。

假如只有 binlog,当 Server 层 binlog 日志写完后 引擎层还没有同步到磁盘就断电了。这个时候重启后 binlog 记录了更新操作,但是引擎层并没有写入磁盘中就导致了从库使用该 binlog 同步数据不一致。

redo log、 binlog 的 差异

  1. redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。
  2. redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”。
  3. redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

Update 语句执行流程

有了对两个日志的概念理解,我们就可以继续理解执行器与 InnoDB 引擎执行 update 语句时的内部流程。

  1. Server 层的执行器先调用引擎取出 ID=2 这一行。ID 是主键,引擎直接用树搜索找到这一行。如果 ID=2 这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。
  2. 执行器拿到数据把这个值 + 1,得到新一行的数据,再调用存储引擎接口写入这行新数据。
  3. InnoDB 引擎将这行数据更新到内存中,同时将这个更新操作所影响的页日志记录到 redo log 中,此时日志处于 prepare 状态,然后会告知 执行器完成了,随时可以提交事务。
  4. 执行器生成这个操作的 binlog ,并把 binlog 写入磁盘。
  5. 执行器继续调用引擎的的提交事务接口,引擎收到请求就把刚刚写入的 redo log 的状态改成提交(commit),更新完成。

最后三步看上去有点“绕”,将 redo log 的写入拆成了两个步骤:

prepare 和 commit,这就是"两阶段提交"。

如下图所示,绿色代表执行器执行,白色代表 InnoDB 引擎执行:

两阶段提交

为什么必须有“两阶段提交”呢?这是为了让两份日志之间的逻辑一致。要说明这个问题,我们得从文章开头的那个问题说起:怎样让数据库恢复到半个月内任意一秒的状态?

前面我们说过了,binlog 会记录所有的逻辑操作,并且是采用“追加写”的形式。如果你的 DBA 承诺说半个月内可以恢复,那么备份系统中一定会保存最近半个月的所有

binlog,同时系统会定期做整库备份。这里的“定期”取决于系统的重要性,可以是一天一备,也可以是一周一备。

当需要恢复到指定的某一秒时,比如某天下午两点发现中午十二点有一次误删表,需要找回数据,那你可以这么做:

  1. 首先,找到最近的一次全量备份,如果你运气好,可能就是昨天晚上的一个备份,从这个备份恢复到临时库;
  2. 然后,从备份的时间点开始,将备份的 binlog 依次取出来,重放到中午误删表之前的那个时刻。

由于 redo log 和 binlog 是两个独立的逻辑,如果不用两阶段提交,要么就是先写完 redo log 再写 binlog,或者采用反过来的顺序。我们看看这两种方式会有什么问题。(会造成数据不一致)

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

先写 redo log 后写 binlog

假如在引擎 写完 redo log 后,bin log 没有写完,异常重启,依然可以根据 redo log 日志把数据恢复,但是 binlog 没有记录这个语句。 所以从库 通过 binlog 同步数据就导致没有把这个这行数据同步过来,丢失了这个事务操作造成数据不一致。

先写 binlog 再写 redo log

如果写完 binlog 后 崩溃,由于 redo log 还没有写,崩溃恢复后这个事务无效,但是 binlog 却有记录。从库根据 这个 binlog 日志就会导致多处一个事务,与主库不一致。

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


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
5天前
|
SQL 存储 缓存
MySQL执行流程
本文介绍了MySQL的执行流程,分为server层和引擎层。server层包含连接器、查询缓存、解析器、预处理器、优化器等组件,负责SQL的接收、解析、优化及执行;引擎层负责数据的存储与读取。文章详细解释了各组件的功能,如连接器负责用户身份认证,查询缓存提高查询效率,解析器进行SQL的词法和语法分析,预处理器验证表和字段的存在性,优化器选择最优执行计划,最终由查询执行引擎完成查询并将结果返回给客户端。
MySQL执行流程
|
2月前
|
SQL 存储 关系型数据库
美团面试:binlog、redo log、undo log的底层原理是什么?它们分别实现ACID的哪个特性?
老架构师尼恩在其读者交流群中分享了关于 MySQL 中 redo log、undo log 和 binlog 的面试题及其答案。这些问题涵盖了事务的 ACID 特性、日志的一致性问题、SQL 语句的执行流程等。尼恩详细解释了这些日志的作用、所在架构层级、日志形式、缓存机制以及写文件方式等内容。他还提供了多个面试题的详细解答,帮助读者系统化地掌握这些知识点,提升面试表现。此外,尼恩还推荐了《尼恩Java面试宝典PDF》和其他技术圣经系列PDF,帮助读者进一步巩固知识,实现“offer自由”。
美团面试:binlog、redo log、undo log的底层原理是什么?它们分别实现ACID的哪个特性?
|
1月前
|
存储 SQL NoSQL
|
2月前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1684 14
|
2月前
|
存储 关系型数据库 MySQL
MySQL中的Redo Log、Undo Log和Binlog:深入解析
【10月更文挑战第21天】在数据库管理系统中,日志是保障数据一致性和完整性的关键机制。MySQL作为一种广泛使用的关系型数据库管理系统,提供了多种日志类型来满足不同的需求。本文将详细介绍MySQL中的Redo Log、Undo Log和Binlog,从背景、业务场景、功能、底层实现原理、使用措施等方面进行详细分析,并通过Java代码示例展示如何与这些日志进行交互。
188 0
|
3月前
|
存储 缓存 关系型数据库
redo log 原理解析
redo log 原理解析
50 0
redo log 原理解析
|
3月前
|
SQL 缓存 关系型数据库
揭秘MySQL一条SQL语句的执行流程
以上步骤共同构成了MySQL处理SQL语句的完整流程,理解这一流程有助于更有效地使用MySQL数据库,优化查询性能,及时解决可能出现的性能瓶颈问题。
103 7
|
2月前
|
SQL 关系型数据库 MySQL
MySQL异常一之: You can‘t specify target table for update in FROM clause解决办法
这篇文章介绍了如何解决MySQL中“不能在FROM子句中指定更新的目标表”(You can't specify target table for update in FROM clause)的错误,提供了错误描述、需求说明、错误做法和正确的SQL写法。
650 0
|
4月前
|
API C# 开发框架
WPF与Web服务集成大揭秘:手把手教你调用RESTful API,客户端与服务器端优劣对比全解析!
【8月更文挑战第31天】在现代软件开发中,WPF 和 Web 服务各具特色。WPF 以其出色的界面展示能力受到欢迎,而 Web 服务则凭借跨平台和易维护性在互联网应用中占有一席之地。本文探讨了 WPF 如何通过 HttpClient 类调用 RESTful API,并展示了基于 ASP.NET Core 的 Web 服务如何实现同样的功能。通过对比分析,揭示了两者各自的优缺点:WPF 客户端直接处理数据,减轻服务器负担,但需处理网络异常;Web 服务则能利用服务器端功能如缓存和权限验证,但可能增加服务器负载。希望本文能帮助开发者根据具体需求选择合适的技术方案。
197 0
|
1月前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
263 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板