这期的文章主要是讲述写操作过程中涉及到的三个日志文件,看过前几期的话可能你或多或少已经有些了解了(或者从别的地方也了解过)。比如整个写操作过程中用到的两阶段提交,又或者是操作过程中涉及到的日志文件,但是总体来说不是很系统更谈不上全面。

今天我们就来会会这三兄弟。

图注:思维导图

两阶段提交

这个名词你应该听到过很多次了,在这里再介绍下这位老朋友。

所谓的两阶段提交,从字面意思来看应该是有两个步骤来进行约束的。事实上也是如此。这两个步骤中的主角就是我们今天要讲的重要角色中的两位:binlog 和 redo log

提到两阶段提交,SQL 语句的执行流程就绕不过去了。没辙,虽然提了很多遍,但还得再拉出来溜溜。只不过这次的侧重点和前面的会有些不同。

具体到操作流程上是这样的:

当执行某个写操作的 SQL 时,引擎将这行数据更新到内存的同时把对应的操作记录到 redo log 里面,然后处于 prepare 状态。并把完成信息告知给执行器。

执行器生成对应操作的 binlog,并把 binlog 写入磁盘里。然后调用引擎的提交事务接口,变更 redo log 状态为 commit,这样操作就算完成了。

好了,知道了两阶段提交后,我们接下来看看这些日志文件的真面目。

重做日志(redo log)

首先出场的是位于存储引擎层的 redo log,它是用来记录在"数据页做了什么修改"的物理日志文件。

WAL 技术

提到 redo log,WAL 技术必然是绕不过去的,全称是 Write-Ahead Logging。也就是在同步磁盘前先写日志,然后系统再根据一定的策略将日志里的记录同步到磁盘里。

存在的必要性

从上边的两阶段提交的过程里,我们可以看到 WAL 技术的使用场景。不知道你有没有疑惑,为什么中间非要写 redo log,直接将更新结果同步到磁盘里不行吗?傻孩子,同步到磁盘里就意味着每次写操作就得产生随机写盘操作,速度得多慢啊。

机智的你可能会说了,那我能不能一定的时间后从内存再同步到磁盘里,这种方式不行吗?来,先给你个脑瓜崩,你想想,我服务重启了,这些数据还在不?内存是易失的,不知道什么异常情况就会导致数据丢失。所以这时候就需要一个能持久化的中间文件,起到"缓冲"的作用,并且写入速度还不慢。

那么 redo log 就应运而生了。虽然同样存储在磁盘上,但是顺序写入在速度上并不受影响(疑惑的同学可以了解下磁盘的随机与顺序读写的区别)。

当然 redo log 除了能起到"延迟"同步磁盘文件的作用外,在数据库服务器宕机时,还可以用来恢复数据。

写入时机

谈到写入时机,是不是更疑惑了,难倒不是更新完内存就写入 redo log 文件吗?答案确实不是,因为中间还有一个 redo log buffer(内存中) 。Mysql 每执行一条语句,会先将记录写入 redo log buffer,后续执行 commit 操作时会以一定的时机写入到 redo log 文件(磁盘上)中。

值得注意的是,redo log buffer 里的数据是在执行 commit 操作时写入到 redo log 文件中的。

至于写入的时机,则由下面的参数来控制的:

 

(图片源自网络)

写入方式

知道了写入时机,这里简单介绍下写入的方式吧。在 Innodb 中,redo log 的大小是固定的,那么就只能是以循环的方式进行写入了。假如当前我有 4 个文件,从第一个文件开始写入,直到最后一个文件写满为止,再回到开头将数据同步至文件后擦除掉继续写。

图中的 write pos 表示当前记录的位置,随着不断写入逐渐后移。当写到 ib_logfile_3号文件时,整个 redo log 就被写满了。此时更新操作就会被阻塞。系统根据 check point 标记位来擦除掉一些记录(当然前提是把这些记录同步至磁盘)。

总得来看 redo log 的写入方式就是一个不断写入,写满后擦除,又写入的过程。

二进制日志(binlog)

说完了 redo log,我们再来看看另一个位于服务层的二进制日志文件 binlog,这位大兄弟扮演的角色是存储逻辑日志的,所谓的逻辑日志就是指修改了什么,都会记录其中。

例如:对 id = 1 的字段进行更新操作。

当然除了记录操作过程外,它还有支持主从同步数据异常恢复的能力。

写入模式

binlog 中有三种写入模式,我们分别来看下有什么不同及对应的优缺点:

(图片源自网络)

写入方式

与 redo log 循环写不同的是, binlog 采用追加的方式写入,当一个文件写到一定大小后就会切换到另一个。

与 redo log 的关联

在上面的两阶段提交里我们有提到过在写入binlog 后会调用引擎的提交事务接口,变更 redo log 状态为 commit。那么它是如何找到对应的记录,或者换句话说,它们两者是怎么关联起来的呢?

答案是通过一个共同的字段 XID,不仅在事务提交时,在崩溃恢复的时候如果遇到仅写入 prepare 而没有 commit 的 redo log,也可以通过 XID 去寻找对应的事务。

回顾下写流程

到这里我们有必要回顾下写流程的操作,以更新某个字段为例:

回滚日志(undo log)

到这里,你可能会疑惑了,通篇里哪有 undo log 的影子,你个渣男!

别急,来了!

根据字面意思,你应该能猜出来它是干啥的。回滚嘛,也就是给你一次后悔的机会。在进行数据修改时,同时记录 undo log,即同时记录相反操作的逻辑日志。你可以理解为操作 update 的时候,写一条对应相反的 update 记录,操作 delete 的时候,写一条对应的 insert 记录。

当事务回滚时。从 undo log 中读取到对应的逻辑记录就可以进行回滚操作了。

总结

两阶段提交

  • 两阶段提交过程中,更新内存的同时把对应操作记录到 redo log 中,并把生成的binlog 写入磁盘后提交事务。

重做日志 

  • redo log 是位于存储引擎层的物理日志,用来记录在“数据页做了什么修改”的物理日志文件。采用循环写的方式,记录数据被修改后的样子。同时还提供数据恢复的能力。

二进制日志

  • binlog是位于服务层的逻辑日志,用来记录“对数据做了什么修改”的日志文件。与 redo log 不同的是,可以一直进行追加写入。同时还提供主从同步及数据异常恢复的能力。

回滚日志 

  • 在数据修改时,同时记录 undo log,可以确保在事务回滚操作时进行数据还原。

关于作者

作者:大家好,我是莱乌,BAT搬砖工一枚。从小公司进入大厂,一路走来收获良多,想将这些经验分享给有需要的人,因此创建了公众号【IT界农民工】。定时更新,希望能帮助到你。同时,我给大家肝了一份Redis面经手册,在我的公众号内回复【pdf】即可获取,希望对你有所帮助。

Mysql 中写操作时保驾护航的三兄弟!的更多相关文章

  1. MySQL中写操作

    具体到操作流程: 当执行某个写操作的 SQL 时,引擎将这行数据更新到内存的同时把对应的操作记录到 redo log 里面,然后处于 prepare 状态.并把完成信息告知给执行器. 执行器生成对应操 ...

  2. 【科普】MySQL中DDL操作背后的并发原理

    一. 简介 DQL:指数据库中的查询(select)操作. DML:指数据库中的插入(insert).更新(update).删除(delete)等行数据变更操作. DDL:指数据库中加列(add co ...

  3. Access 中数据库操作时提示from子句语法错误

    问题:如果在Access 中数据库操作时提示from子句语法错误原因:语句中某一单词为Access中的关键字.如:select * from user.其中user就是一关键字.解决:用中括号[]将其 ...

  4. mysql中float、double、decimal三种类型,以及数值产生误差的原因

    单精度浮点数用4字节(32bit)表示浮点数,采用IEEE754标准的计算机浮点数,在内部是用二进制表示的,如:7.22用32位二进制是表示不下的,所以就导致不精确了,存取会出现误差. mysql中f ...

  5. MySQL中处理Null时要注意两大陷阱

    MySQL数据库是一个基于结构化数据的开源数据库.SQL语句是MySQL数据库中核心语言.不过在MySQL数据库中执行SQL语句,需要小心两个陷阱. 陷阱一:空值不一定为空 空值是一个比较特殊的字段. ...

  6. Python在mysql中进行操作是十分容易和简洁的

    首先声明一下,我用的是Windows系统! 1.在Python中对mysql数据库进行操作首先要导入pymysql模块,默认情况下,Python中是没有安装这个模块的, 可以在Windows的命令行中 ...

  7. 在Navicat for MySQL中打开视图时,提示视图没有主键的问题

    一直把视图理解为一个select语句而已,视图一般就是用于查询,不会通过视图来更新表或视图本身的数据,所以视图根本不需要什么主键.今天自己建了一个视图view_test: drop view if e ...

  8. 解决python中write()函数向文件中写中文时出现乱码的问题

    今天看<python编程从入门到实践>的第10章文件.异常,在做练习的时候,向文件中写内容,但是写中文就不行,后来在百度上查了众多资料,解决方法如下: 解决:在open()函数中添加一个e ...

  9. mysql批量update操作时出现锁表

    https://www.cnblogs.com/wodebudong/articles/7976474.html 最近遇到一件锁表的情况,发现更新的语句where检索的字段,没有建索引,且是批量操作的 ...

随机推荐

  1. 使用gitlab-runner本地验证.gitlab-ci.yml

    背景 在gitlab上配置新项目的CI的时候,需要编写项目的 .gitlab-ci.yml 文件. 每次修改 .gitlab-ci.yml 文件之后都要执行git push让GitLab去构建来验证当 ...

  2. 如何在Python中处理不平衡数据

    Index1.到底什么是不平衡数据2.处理不平衡数据的理论方法3.Python里有什么包可以处理不平衡样本4.Python中具体如何处理失衡样本印象中很久之前有位朋友说要我写一篇如何处理不平衡数据的文 ...

  3. Argo CD使用指南:如何构建一套完整的GitOps?

    随着Kubernetes继续将自己确立为容器编排的行业标准,为你的应用和工具找到使用声明式模型的有效方法是成功的关键.在这篇文章中,我们将在AWS中建立一个K3s Kubernetes集群,然后使用A ...

  4. 使用Python实现搜索任意电影资源的磁力链接

    对于喜欢电影的人来说各种电影资源必不可少,但每次自己搜索都比较麻烦,索性用python自己写一个自动搜索的脚本. 这里我只分享我的思路,具体如何实现参考代码,要想实现搜索功能先要抓包分析如何发送数据, ...

  5. 在 easyui中获取form表单中所有提交的数据 拼接到table列表中

    form表单===== <!-- 并用药品填写信息弹框 --> <div id="usingProdctMsgDiv" style="display: ...

  6. 【代码周边】Idea设置类注解和方法注解(带图)

    Idea版本: 类注解 打开setting→Editor→Code Style→File and Code Templates /** * Created with IntelliJ IDEA. * ...

  7. request.getContextPath()返回值问题

    转自:http://blog.sina.com.cn/s/blog_6cbe0cff0101j6jl.html request.getContextPath()是在开发Web项目时,经常用到的方法,其 ...

  8. 分析http协议和高并发网站架构

    案例任务名称 分析http协议和高并发网站架构 案例训练目标 深入理解http协议的工作原理 掌握http协议的分析方法 包含技能点 搭建web服务器 编辑简单的html页面并上传到服务器 使用wir ...

  9. 耗子大叔弹窗来自百度搜索引擎导流的弹窗JS源码赏析

    刚看到https://coolshell.cn/articles/9308.html 耗子大叔评价梁斌站点被百度封杀事件言论  然后在自己个人网站酷壳网站上发布了一段JS代码  当请求来自百度导流过来 ...

  10. mysql事务_事务隔离级别详解

    使用事务语法 1. 开启事务start transaction,可以简写为 begin 2. 然后记录之后需要执行的一组sql 3. 提交commit 4. 如果所有的sql都执行成功,则提交,将sq ...