一次讲清楚MySQL与InnoDB存储引擎的架构设计

目录

一、MySQL的架构设计

1.1 SQL接口

1.2 查询解析器

1.3 查询优化器

1.4 存储引擎执行SQL语句

二、InnoDB存储引擎的架构设计

2.1 缓冲池(Buffer Pool)

2.2 undo日志

2.3 redo日志(Redo Log Buffer)

2.4 提交事务的时候将redo日志写入磁盘中

等于0时

等于1时

等于2时

三、binlog日志

3.1 binlog刷盘策略

sync_binlog等与0时

sync_binlog等与1时

3.2 基于binlog和redo log完成事务的提交

3.3 后台IO线程随机将内存更新后的脏数据刷回磁盘


一、MySQL的架构设计

首先当我们通过数据库连接发送给MySQL一条sql语句时,MySQL会怎么操作呢?

1.1 SQL接口

他是一套执行SQL语句的接口,专门用于执行我们发送给MySQL的那些增删改查的SQL语句,当MySQL接收到我们发送的SQL语句时,会交给SQL接口去执行这条语句。

1.2 查询解析器

那么问题来了,SQL接口是怎么执行SQL语句的呢?

首先比如我们发送一条语句是这样的:

select id, name, age from user where id = 1;

我们能看得懂这条SQL的意思,但是MySQL要是想看懂,就需要查询解析器了。

所谓的SQL解析,就是按照既定的SQL语法,对我们按照SQL语法规则编写的SQL语句进行解析,然后理解这个SQL语句要干什么事情。

1.3 查询优化器

当我们通过解析器理解了SQL语句要干什么之后,接着会找查询优化器(Optimizer)来选择一个最优的查询路径。

就是你这条SQL怎么执行最好、最快、效率最高是由查询优化器决定的,我们都知道SQL语句加索引能优化查询,但你以为加了索引就一定更好吗?有的时候你加了索引并查询,MySQL的优化器依然没有用索引,而是通过全表扫描,因为优化器认为,有些时候全表扫描比你加了索引查询还要好。

1.4 存储引擎执行SQL语句

最后按照优化器给的最优路径,存储引擎执行SQL语句。

那么问题又来了,既然叫做存储引擎,那么我们update的数据,或者select的数据,都存在哪啊?无非就是内存或者硬盘,那到底是存在内存还是硬盘呢?接着听我分析下一章节。

二、InnoDB存储引擎的架构设计

MySQL最常用的就是InnoDB存储引擎,那么我们今天借助一条更新语句的执行,来初步的了解一
下InnoDB存储引擎的架构设计。

update users set name='xxx' where id=10;

那么这条语句是怎么执行的呢?我们接着上一章节的架构图来补充。

2.1 缓冲池(Buffer Pool)

InnoDB存储引擎中有一个非常重要的放在内存里的组件,就是缓冲池(Buffer Pool),这里面会缓存很多的数据,以便于以后在查询的时候,万一你要是内存缓冲池里有数据,就可以不用去查磁盘了。

引擎要执行更新语句的时候 ,比如对“id=10”这一行数据,他其实会先将“id=10”这一行数据看看是否在缓冲池里,如果不在的话,那么会直接从磁盘里加载到缓冲池里来。

2.2 undo日志

学过数据库的都知道事务,我们增删改的时候必须最后要提交事务,才能真正的修改数据,如果事务过程中出现了问题,我们可以进行回滚,将数据恢复原来的样子,undo日志就是用来干这个的。

假如“id=10”这一行数据缓冲池没有,那么就从磁盘上获取,并加载到缓冲池中,并且把旧值写入undo日志文件里,防止出现问题可以及时回滚。当把旧值写入undo日志文件中时,更新缓冲池里的数据,这时候属于“脏数据”,因为缓冲池是新数据,但磁盘却是旧数据。

架构图如下:

2.3 redo日志(Redo Log Buffer)

那么按上面的架构图来说,第三步更新缓冲池数据完毕,这时要把对内存所做的修改写入到一个Redo Log Buffer里去,这也是内存里的一个缓冲区,是用来存放redo日志的。

所谓的redo日志,就是记录下来你对数据做了什么修改,比如对“id=10这行记录修改了name字段的值为xxx”,这就是一个日志。

那么问题来了,这时MySQL宕机了,内存数据全部丢失,该怎么办?

其实不用慌,内存数据虽然丢失了,但你磁盘上真实数据还是旧的数据,你顶多这次操作不成功,数据不会有什么影响的。

2.4 提交事务的时候将redo日志写入磁盘中

接着我们想要提交一个事务了,此时就会根据一定的策略把redo日志从redo log buffer里刷入到磁盘文件里去。

此时这个策略是通过innodb_flush_log_at_trx_commit来配置的,他有几个选项。

等于0时

当这个参数的值为0的时候,那么你提交事务的时候,不会把redo log buffer里的数据刷入磁盘文件的,此时可能你都提交事务了,结果mysql宕机了,然后此时内存里的数据全部丢失。相当于你提交事务成功了,但是由于MySQL突然宕机,导致内存中的数据和redo日志都丢失了。

等于1时

当这个参数的值为1的时候,你提交事务的时候,就必须把redo log从内存刷入到磁盘文件里去,那么只要提交事务成功之后,redo日志一定在磁盘文件里,就算这个时候宕机,等重启MySQL后,自动读取磁盘里的redo日志,恢复之前做的修改。

注意:这时只是redo写入到redo日志磁盘文件中,并没有直接修改磁盘里的数据。

等于2时

提交事务的时候,把redo日志写入磁盘文件对应的os cache缓存里去,而不是直接进入磁盘文件,可能1秒后才会把os cache里的数据写入到磁盘文件里去。

这种模式下,你提交事务之后,redo log可能仅仅停留在os cache内存缓存里,没实际进入磁盘文件,万一此时你要是机器宕机了,那么os cache里的redo log就会丢失,同样会让你感觉提交事务了,结果数据丢了。

三、binlog日志

实际上我们之前说的redo log,他是一种偏向物理性质的重做日志,因为他里面记录的是类似这样的东西,“对哪个数据页中的什么记录,做了个什么修改”。

而且redo log本身是属于InnoDB存储引擎特有的一个东西。

而binlog叫做归档日志,他里面记录的是偏向于逻辑性的日志,类似于“对users表中的id=10的一行数据做了更新操作,更新以后的值是什么”。

binlog不是InnoDB存储引擎特有的日志文件,是属于mysql server自己的日志文件。

所以其实我们上一讲讲到,在我们提交事务的时候,会把redo log日志写入磁盘文件中去。然后其实在提交事务的时候,我们同时还会把这次更新对应的binlog日志写入到磁盘文件中去。

3.1 binlog刷盘策略

sync_binlog等与0时

他的默认值是0,此时你把binlog写入磁盘的时候,其实不是直接进入磁盘文件,而是进入os cache内存缓存。

所以跟之前分析的一样,如果此时机器宕机,那么你在os cache里的binlog日志是会丢失的。

sync_binlog等与1时

如果要是把sync_binlog参数设置为1的话,那么此时会强制在提交事务的时候,把binlog直接写入到磁盘文件里去,那么这样提交事务之后,哪怕机器宕机,磁盘上的binlog是不会丢失的。

3.2 基于binlog和redo log完成事务的提交

当我们把binlog写入磁盘文件之后,接着就会完成最终的事务提交,此时会把本次更新对应的binlog文件名称和这次更新的binlog日志在文件里的位置,都写入到redo log日志文件里去,同时在redo log日志文件里写入一个commit标记。在完成这个事情之后,才算最终完成了事务的提交

那么标记的意义是什么?

说白了,他其实是用来保持redo log日志与binlog日志一致的。

比如第五步完成后宕机了,那么事务就算没有完成,就会回滚。同理第六步完成后宕机了,一样没有在redo log日志中写入commit标记,一样算没有完成,同样会回滚。

3.3 后台IO线程随机将内存更新后的脏数据刷回磁盘

如果所有步骤都完成了,redo log日志中也写入了commit标记,那么就等MySQL后台的IO线程,会在之后某个时间里,随机的把内存buffer pool中的修改后的脏数据给刷回到磁盘上的数据文件里去。

最终版架构图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Calvad0s

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值