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检索的字段,没有建索引,且是批量操作的 ...
随机推荐
- Laravel Argument 1 passed to App\Models\Recipients\AlertRecipient::__construct() must be an instance of App\Models\Recipients\string, string given,
今天测试snipet的计划任务,库存低于警告值的时候,时候会会自动发送邮件到邮箱 class SendInventoryAlerts extends Command { /** * The name ...
- Maven史上最全的pom.xml详解
下面主要是借鉴 官网的资料 收集而来 主要是为了讲解,用到的很少,但是还是需要了解 ,重点是方便查验资料 <project xmlns="http://maven.apache.org ...
- Python机器学习课程:线性回归算法
本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理 最基本的机器学习算法必须是具有单个变量的线性回归算法.如今,可用的高级机器学习算法,库和技术如此之多 ...
- ARP局域网断网攻击
Kali--ARP局域网攻击 什么是ARP? ARP ( Address Resolution Protocol)地址转换协议,工作在OSI模型的数据链路层,在以太网中,网络设备之间互相通信是用MAC ...
- java中定时器设置时间
<!-- 0 0 10,14,16 * * ? 每天上午10点,下午2点,4点 0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时 0 0 12 ? * WED 表示每个星期三中午1 ...
- 一致性HASH算法在分布式应用场景使用
其实不管redis还好,Mysql也好 这种数据存储介质,在分布式场景中都存在共同问题:即集群场景下服务路由.比如redis集群场景下,原本我们分3主3从部署.但万一有一天出现访问量暴增或其中一台机器 ...
- Centos7上以RPM包方式安装Oracle 18c XE
Centos7上以RPM包方式安装Oracle 18c XE 安装阿里云 YUM 源 https://opsx.alibaba.com/mirror?lang=zh-CN 一.安装oracle数据库 ...
- Java并发包源码学习系列:AQS共享式与独占式获取与释放资源的区别
目录 Java并发包源码学习系列:AQS共享模式获取与释放资源 独占式获取资源 void acquire(int arg) boolean acquireQueued(Node, int) 独占式释放 ...
- ES6+Webpack+Babel基本环境搭建
### 本文基本是流水文,记录学习中步骤,希望对看到的你有用,蟹蟹. 基本环境搭建 技术栈 Webpack ES6 Babel 开发环境 VS Code Node 搭建环境过程 新建项目文件夹
- LinkedList 的 API 与数据结构
LinkedList 是 List 接口和 Deque 接口的双向链表实现,它所有的 API 调用都是基于对双向链表的操作.本文将介绍 LinkedList 的数据结构和分析 API 中的算法. 数据 ...