MySQL Server系统架构

1. 概述


MySQL的系统架构中,可以分为:客户端、服务端、存储引擎三个部分。其示意图如下:

MySQL系统架构图

今天我们主要关注一下MySQL Server的部分,关于存储引擎部分可以看下“MySQL存储引擎介绍”。

下面将从查询语句和更新语句的执行过程来介绍MySQL Server都有哪些组成部分。

2. 查询语句的执行


假设我们有一条普通的查询语句,MySQL内部是如何执行它的呢? 查询语句如下:

select * from user where id = 123;

下面是MySQL的基本架构图,我们从中可以看到SQL语句的执行过程

2.1. 连接器

要使用MySQL,第一步就是连接到数据库,可以使用mysql -u root -p命令使客户端和mysql服务端建立连接,这个时候会使用到连接器。连接器负责和客户端建立TCP连接、获取权限、维护和管理连接

2.2.1. wait_timeout

客户端和MySQL服务端建立连接之后,如果客户端长时间不使用这个连接,MySQL会自动断开这个连接,具体时间是通过配置参数wait_timeout来控制,默认为8个小时。

如果在连接被断开之后,再基于这个连接发起请求,就会报错。若想再请求需要创建新的连接。

这里请思考一下,为啥我们有些跑批程序(或者执行间隔很长,超过wait_timeout的应用)貌似没有遇到过这个问题,这是因为使用了数据库连接池了,数据库连接池解决这类问题有两个思路:

  1. 配置空闲连接的存活时间,存活时间小于数据库的wait_timeout即可;
  2. 连接空闲多久(时间一般都可配置)之后就往数据库请求'select 1 from dual',数据库收到请求后会重置wait_timeout

2.2.2. 长连接和短连接

在数据库中,如果客户端建立起一个连接之后,持续有请求且都是使用同个连接则称为长连接。而一个连接只请求几次就断开连接,这种称为短连接

因此,一般而言数据库连接池由于实现了连接复用,所以是长连接。而JDBC(只要未实现连接复用)则是短连接。

2.2. 查询缓存

查询缓存是是个K-V对的形式,key是查询的sql,value是查询的结果。在开启查询缓存的情况下,建立好连接后,就会去查询缓存中看要查询的语句是否在缓存当中。如果在缓存中,就直接给客户端返回。

一般来说,不推荐使用查询缓存,主要是因为查询缓存的释放很频繁。只要对某个进行了更新,所有基于这张表的查询缓存都将会失效。另外在MySQL 8.0中已经将查询缓存模块删除

2.3. 分析器

分析器模块主要包括两大功能:

  1. 词法分析
  2. 语义分析

一般先做词法分析,词法分析完之后再进行语义分析。

词法分析是从是输入的语句select * from user where id = 123中,将select关键字识别出来,代表着这是条查询语句,将user识别成表,将id识别成列。

语义分析是分析你输入的SQL语句是否符合SQL语法规范。

2.4. 优化器

我们的语句经过分析器之后,MySQL就知道了你想做什么,但是在具体执行之前,还要先经过优化器优化。

优化器主要是生成执行计划,它会根据语句在多个索引中选择最合适的索引,在有join的语句中,决定各个表的连接顺序。

2.5. 执行器

进行执行器就是要执行语句了,不过在执行之前,会先判断你是否有对这个表的执行权限。

有权限的话,执行器先查询表的存储引擎是什么,查询到存储引擎,就调用存储引擎提供的接口来执行查询,然后再获取存储引擎返回的结果。

3. 更新语句的执行


假设现在要执行以下更新SQL,我们一起来看看其执行过程

update user set name = 'zs' where id =123;

和查询语句的执行流程一样,其也会先进行连接,连接成功后,分析器分析出是一条更新语句,优化器选择id索引,执行器找到id=123的记录然后再进行更新。

除了上面同样的流程之外,由于更新语句涉及到了数据的更改,所以MySQL未更新语句的执行引入日志模块。主要涉及到两个日志文件: redo和binlog

3.1. redo

在了解MySQL是如何执行一笔更新操作之前,如果我们自己来实现,我们可能会这样做:更新操作直接写进磁盘,然后磁盘先找到对应的记录,再将其更新。这种方式当然可行,不过它的IO成本比较高(随机写)。

MySQL采用的是一种称为WAL(Write-Ahead Logging,日志先行)的方案,即MySQL会将要更新的记录先写到日志文件(即redo log)中,并更新内存,然后就可以返回客户端更新成功,最后在系统比较空闲的时候再将内存中(buffer pool)的操作记录更新到磁盘(数据实际存储的文件)中

redo log是Innodb中的日志文件,有了redo文件,即使MySQL服务突然宕机了,可以在系统恢复之后,根据redo log文件的内容进行重做。从而保证了之前的记录不会丢失。这种能力我们称之为“crash safe”

3.1.1. redo log相关参数

我们可以通过show variables like "%innodb_log%";命令查看和redo log有关的系统参数,主要有以下几个:

innodb_log_file_size        ## 指定redo log日志文件的大小
innodb_log_files_in_group   ##redo log日志文件组中文件的数量,默认2个,ib_logfile0和ib_logfile1
innodb_log_buffer_size      ##redo log buffer的大小

3.1.2. redo log示意图

例如我们配置为一组4个文件,每个文件的大小是1G,那么一共就可以记录4G的记录。redo log是个环形的写入方式,从头开始写,写到末尾又从头开始写,以下是示意图:


图片来源于极客时间-MySQL45讲

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

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

3.1.3. 写redlog为啥会快

看到这里,不知道你有没有这样的疑惑:写redo log日志为啥笔直接写磁盘要快?

redo log是直接追加写,它是顺序写,而直接写磁盘是随机写

连续 I/O 比随机 I/O 效率高的原因是:在做连续 I/O 的时候,磁头几乎不用换道,或者换道的时间很短;而对于随机 I/O,如果这个 I/O 很多的话,会导致磁头不停地换道,造成效率的极大降低。

3.2. binlog

binlog是记录所有数据库表结构变更(例如CREATE、ALTER TABLE…)以及表数据修改(INSERT、UPDATE、DELETE…)的二进制日志。它采用追加写的方式来记录日志。

binlog的主要作用有:恢复(删库了进行恢复)、复制(主从架构中,从主节点复制到从节点)、审计(判断是否有对数据库进行注入攻击)

有了redo log,我们可以保证并发事务操作下以及数据库异常时数据页中数据的一致性。那为啥还需要有binlog日志呢?这是因为redo log是属于Innodb存储引擎的,而binlog属于MySQL Server。先有MySQL,后有Innodb,而binlog日志只能用于归档、数据的实时备份。binlog是不具有crash save的功能。

3.3. update语句的执行流程

下面是update语句的执行流程图,和查询语句相同的执行流程这里不再体现,直接从执行器开始。

从图上我们可以看到,写redolog分成了preparecommit两步,这就是 两阶段提交

3.4. 两阶段提交

MySQL之所以使用两阶段提交,是因为使用两阶段提交可以保障数据库状态和用日志恢复出来的数据库状态一致

假如不是使用两阶段提交,我们分析下会有什么问题:

  1. 先写redo log,再写binlog,中间发生crash的话,redo log就会有更新记录,而binlog丢失了该次更新。重启之后由于redo log有记录,所以数据能够恢复,而使用binlog恢复的备份库会缺少更新的数据。
  2. 先写binlog,再写redo log,这种情况正好相反,同步备库时binlog里有更新的记录,所以备库有这条更新的记录,而redo log没有记录,所以主库就丢了本次更新。

两阶段提交也可能会发生异常,它的异常点有:1.写入binlog发生异常,2. 提交事务发生异常。

  • 若在写入binlog日志时发生异常
    由于此时 binlog 还没写,redo log 也还没提交,所以崩溃恢复的时候,这个事务会回滚。这时候,binlog 还没写,所以也不会传到备库。
  • 若binlog日志写完之后发生了异常
    崩溃恢复时的判断规则:
    如果 redo log 里面的事务是完整的,也就是已经有了 commit 标识,则直接提交。
    如果 redo log 里面的事务只有完整的 prepare,则判断对应的事务 binlog 是否存在并完整:
    • a. 如果是,则提交事务
    • b. 否则,回滚事务
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容