Mysql 中写操作时保驾护航的三兄弟!
这期的文章主要是讲述写操作过程中涉及到的三个日志文件,看过前几期的话可能你或多或少已经有些了解了(或者从别的地方也了解过)。比如整个写操作过程中用到的两阶段提交,又或者是操作过程中涉及到的日志文件,但是总体来说不是很系统更谈不上全面。
今天我们就来会会这三兄弟。
图注:思维导图
两阶段提交
这个名词你应该听到过很多次了,在这里再介绍下这位老朋友。
所谓的两阶段提交,从字面意思来看应该是有两个步骤来进行约束的。事实上也是如此。这两个步骤中的主角就是我们今天要讲的重要角色中的两位: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 中写操作时保驾护航的三兄弟!的更多相关文章
- MySQL中写操作
具体到操作流程: 当执行某个写操作的 SQL 时,引擎将这行数据更新到内存的同时把对应的操作记录到 redo log 里面,然后处于 prepare 状态.并把完成信息告知给执行器. 执行器生成对应操 ...
- 【科普】MySQL中DDL操作背后的并发原理
一. 简介 DQL:指数据库中的查询(select)操作. DML:指数据库中的插入(insert).更新(update).删除(delete)等行数据变更操作. DDL:指数据库中加列(add co ...
- Access 中数据库操作时提示from子句语法错误
问题:如果在Access 中数据库操作时提示from子句语法错误原因:语句中某一单词为Access中的关键字.如:select * from user.其中user就是一关键字.解决:用中括号[]将其 ...
- mysql中float、double、decimal三种类型,以及数值产生误差的原因
单精度浮点数用4字节(32bit)表示浮点数,采用IEEE754标准的计算机浮点数,在内部是用二进制表示的,如:7.22用32位二进制是表示不下的,所以就导致不精确了,存取会出现误差. mysql中f ...
- MySQL中处理Null时要注意两大陷阱
MySQL数据库是一个基于结构化数据的开源数据库.SQL语句是MySQL数据库中核心语言.不过在MySQL数据库中执行SQL语句,需要小心两个陷阱. 陷阱一:空值不一定为空 空值是一个比较特殊的字段. ...
- Python在mysql中进行操作是十分容易和简洁的
首先声明一下,我用的是Windows系统! 1.在Python中对mysql数据库进行操作首先要导入pymysql模块,默认情况下,Python中是没有安装这个模块的, 可以在Windows的命令行中 ...
- 在Navicat for MySQL中打开视图时,提示视图没有主键的问题
一直把视图理解为一个select语句而已,视图一般就是用于查询,不会通过视图来更新表或视图本身的数据,所以视图根本不需要什么主键.今天自己建了一个视图view_test: drop view if e ...
- 解决python中write()函数向文件中写中文时出现乱码的问题
今天看<python编程从入门到实践>的第10章文件.异常,在做练习的时候,向文件中写内容,但是写中文就不行,后来在百度上查了众多资料,解决方法如下: 解决:在open()函数中添加一个e ...
- mysql批量update操作时出现锁表
https://www.cnblogs.com/wodebudong/articles/7976474.html 最近遇到一件锁表的情况,发现更新的语句where检索的字段,没有建索引,且是批量操作的 ...
随机推荐
- 用Python从头开始构建神经网络
神经网络已经被开发用来模拟人脑.虽然我们还没有做到这一点,但神经网络在机器学习方面是非常有效的.它在上世纪80年代和90年代很流行,最近越来越流行.计算机的速度足以在合理的时间内运行一个大型神经网络. ...
- 7.自定义ViewGroup-下滑抽屉
1.效果 2.思路 分析效果: 1.布局分为两部分,后面部分,前面部分,默认状态后面被挡住: 2.后面不可以滑动,前面可以滑动: 3.如果前面的布局本身是可以滑动的,那么当前面布局滑动到第一个时,后面 ...
- 常见的JS手写函数汇总(代码注释、持续更新)
最近在复习面试中常见的JS手写函数,顺便进行代码注释和总结,方便自己回顾也加深记,内容也会陆陆续续进行补充和改善. 一.手写深拷贝 <script> const obj1 = { name ...
- [leetcode]64Minimum Path Sum 动态规划
/** * Given a m x n grid filled with non-negative numbers, * find a path from top left to bottom rig ...
- Redis集群搭建采坑总结
背景 先澄清一下,整个过程问题都不是我解决的,我在里面就是起了个打酱油的角色.因为实际上我负责这个项目,整个过程也比较清楚.之前也跟具体负责的同事说过,等过段时间带他做做项目复盘.结果一直忙,之前做的 ...
- 01 . Go之从零实现Web框架(类似Gin)
设计一个框架 大部分时候,我们需要实现一个 Web 应用,第一反应是应该使用哪个框架.不同的框架设计理念和提供的功能有很大的差别.比如 Python 语言的 django和flask,前者大而全,后者 ...
- 2. C++中的引用
1. 引用的基本使用 作用:给变量起别名 语法:数据类型 &别名=原名 注意: 别名数据类型与原名数据类型一致. 引用必须初始化. 引用一旦初始化后,就不可以更改(只能作为一个变量的别名) ...
- Flask 操作Mysql数据库 - flask-sqlalchemy扩展
数据库的设置 Web应用中普遍使用的是关系模型的数据库,关系型数据库把所有的数据都存储在表中,表用来给应用的实体建模,表的列数是固定的,行数是可变的.它使用结构化的查询语言.关系型数据库的列定义了表中 ...
- G客短信平台开发,资源短信功能使用说明
短信平台使用资源短信操作顺序 联系微信:290615413 1:登录客户端 2:点击左侧 发送短信中的,资源短信 3:资源短信申请操作 3.1:选择相应的省市 会显示资源数量. 3.2:然后输入申请 ...
- C++题目东华
1. 定义一个点类Point,其有两个double型的私有数据成员x和y.此外还包含以下公有成员函数: (1)构造函数,给点初始化: (2)setPoint函数,设置点坐标值: (3)distance ...