热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

MySQL整体架构介绍

这篇文章主要介绍了MySQL整体架构的相关资料,帮助大家更好的了解和使用MySQL数据库,感

MySQL 在整体架构上分为 Server 层和存储引擎层。其中 Server 层,包括连接器、查询缓存、分析器、优化器、执行器等,存储过程、触发器、视图和内置函数都在这层实现。数据引擎层负责数据的存储和提取,如 InnoDB、MyISAM、Memory 等引擎。在客户端连接到 Server 层后,Server 会调用数据引擎提供的接口,进行数据的变更。

连接器

负责和客户端建立连接,获取用户权限以及维持和管理连接。

通过 show processlist; 来查询连接的状态。在用户建立连接后,即使管理员改变连接用户的权限,也不会影响到已连接的用户。默认连接时长为 8 小时,超过时间后将会被断开。

简单说下长连接:

优势:在连接时间内,客户端一直使用同一连接,避免多次连接的资源消耗。

劣势:在 MySQL 执行时,使用的内存被连接对象管理,由于长时间没有被释放,会导致系统内存溢出,被系统kill. 所以需要定期断开长连接,或执行大查询后,断开连接。MySQL 5.7 后,可以通过 mysql_rest_connection 初始化连接资源,不需要重连或者做权限验证。

查询缓存

当接受到查询请求时,会现在查询缓存中查询(key/value保存),是否执行过。没有的话,再走正常的执行流程。

但在实际情况下,查询缓存一般没有必要设置。因为在查询涉及到的表被更新时,缓存就会被清空。所以适用于静态表。在 MySQL8.0 后,查询缓存被废除。

分析器

词法分析:

如识别 select,表名,列名,判断其是否存在等。

语法分析:

判断语句是否符合 MySQL 语法。

优化器

确定索引的使用,join 表的连接顺序等,选择最优化的方案。

执行器

在具体执行语句前,会先进行权限的检查,通过后使用数据引擎提供的接口,进行查询。如果设置了慢查询,会在对应日志中看到 rows_examined 来表示扫描的行数。在一些场景下(索引),执行器调用一次,但在数据引擎中扫描了多行,所以引擎扫描的行数和 rows_examined 并不完全相同

不预先检查权限的原因:如像触发器等情况,需要在执行器阶段才能确定权限,在优化器阶段无法验证。

使用 profiling 查看 SQL 执行过程

打开 profiling 分析语句执行过程:

mysql> select @@profiling;
+-------------+
| @@profiling |
+-------------+
|      0 |
+-------------+
1 row in set, 1 warning (0.00 sec)
mysql> set profiling=1;
Query OK, 0 rows affected, 1 warning (0.00 sec)

执行查询语句:

mysql> SELECT * FROM s limit 10;
+------+--------+-----+-----+
| s_id | s_name | age | sex |
+------+--------+-----+-----+
|  1 | z   | 12 |  1 |
|  2 | s   | 14 |  0 |
|  3 | c   | 14 |  1 |
+------+--------+-----+-----+
3 rows in set (0.00 sec)

获取 profiles;

mysql> show profiles;
+----------+------------+--------------------------+
| Query_ID | Duration  | Query          |
+----------+------------+--------------------------+
|    1 | 0.00046600 | SELECT * FROM s limit 10 |
+----------+------------+--------------------------+

mysql> show profile;
+----------------------+----------+
| Status        | Duration |
+----------------------+----------+
| starting       | 0.000069 |
| checking permissions | 0.000008 | 权限检查
| Opening tables    | 0.000018 | 打开表
| init         | 0.000019 | 初始化
| System lock     | 0.000010 | 锁系统
| optimizing      | 0.000004 | 优化查询
| statistics      | 0.000013 |
| preparing      | 0.000094 | 准备
| executing      | 0.000016 | 执行
| Sending data     | 0.000120 |
| end         | 0.000010 |
| query end      | 0.000015 |
| closing tables    | 0.000014 |
| freeing items    | 0.000032 |
| cleaning up     | 0.000026 |
+----------------------+----------+
15 rows in set, 1 warning (0.00 sec)

查询具体的语句:

mysql> show profile for query 1;
+----------------------+----------+
| Status        | Duration |
+----------------------+----------+
| starting       | 0.000069 |
| checking permissions | 0.000008 |
| Opening tables    | 0.000018 |
| init         | 0.000019 |
| System lock     | 0.000010 |
| optimizing      | 0.000004 |
| statistics      | 0.000013 |
| preparing      | 0.000094 |
| executing      | 0.000016 |
| Sending data     | 0.000120 |
| end         | 0.000010 |
| query end      | 0.000015 |
| closing tables    | 0.000014 |
| freeing items    | 0.000032 |
| cleaning up     | 0.000026 |
+----------------------+----------+
15 rows in set, 1 warning (0.00 sec)

MySQL 日志模块

如前面所说,MySQL 整体分为 Server 层和数据引擎层,而每层也对应了自己的日志文件。如果选用的是 InnoDB 引擎,对应的是 redo log 文件。Server 层则对应了 binlog 文件。至于为什么存在了两种日志系统,咱们往下看。

redo log

redo log 是 InnoDB 特有日志,为什么要引入 redo log 呢,想象这样一个场景,MySQL 为了保证持久性是需要把数据写入磁盘文件的。我们知道,在写入磁盘时,会进行文件的 IO,查找操作,如果每次更新操作都这样的话,整体的效率就会特别低,根本没法使用。

既然直接写入磁盘不行,解决方法就是先写进内存,在系统空闲时再更新到磁盘就可以了。但光更新内存不行,假如系统出现异常宕机和重启,内存中没有被写入磁盘的数据就会被丢掉,数据的一致性就出现问题了。这时 redo log 就发挥了作用,在更新操作发生时,InnoDb 会先写入 redo log 日志(记录了数据发生了怎么样的改变),然后更新内存,最后在适当的时间再写入磁盘,一般是找系统空闲的时间做。先写日志,在写磁盘的操作,就是常说到的 WAL (Write-Ahead- Logging)技术。

redo log 的出现,除了在效率上有了很大的改善,还保证了 MySQL 具有了 crash-safe 的能力,在发生异常情况下,不会丢失数据。

在具体实现上 redo log 的大小是固定的,可配置一组为 4 个文件,每个文件 1GB,更新时对四个文件进行循环写入。

write pos 记录当前写入的位置,写完就后移,当第写入第 4 个文件的末尾时,从第 0 号位置重新写入。

check point 表示当前可以擦除的位置,当数据更新到磁盘时,check point 就向后移动。

write pos 和 check point 之间的位置,就是可以记录更新操作的空间。当 write pos 追上 check point ,不在能执行新的操作,先让 check point 去写入一些数据。

可以将 innodb_flush_log_at_trx_commit 设置成 1,开启 redo log 持久化的能力。

binlog

binlog 则是 Server 层的日志,主要用于归档,在备份,主备同步,恢复数据时发挥作用,常见的日志格式有 row, mixed, statement 三种。具体的使用方法可以参见 Binlog 恢复日志这篇。

可以通过 sync_binlog=1 开启 binlog 写入磁盘。

这里对 binlog 和 redo 进行下区分:

  1. 所有者不同,binlog 是 Server 层,所有引擎都可使用。redo log 是 InnoDB 特有的。
  2. 类型不同,binlog 是逻辑日志,记录的是语句的原始逻辑(比 statement)。redo log 是物理日志,记录某个数据页被做了怎样的修改。
  3. 数据写入的方式不同,binog 日志会一直追加,而 redo log 是循环写入。
  4. 功能不同,binlog 用于归档,而 redo log 用于保证 crash-safe.

两阶段提交

下面执行器和 InnoDB 执行 Update 时内部流程:

以更新 update T set c=c+1 where ID=2; 语句为例:

  1. 执行器通过 InooDB 引擎去 ID 所在行,ID 为主键。引擎通过树搜索找到该行,如果该行所在数据页在内存中,返回给执行器。否则先从磁盘读入内存,然后再返回。
  2. 执行器拿到引擎给的数据,将 C 值加 1,等到新的一行,然后通过引擎接口重新写入新数据。
  3. 引擎将该行更新到内存中,同时将该更新操作记录到 redo log 中,并更改 redo log 的状态为 prepare 状态。然后告知执行器,在合适的时间提交事务。
  4. 执行器生成这个操作的 binlog,并将 binlog 写入磁盘。
  5. 执行器调用引擎到的提交事务接口,将刚刚写入的 redo log 改成 commit 状态,更新完成。

浅色为执行器执行,深色为引擎执行。

在更新内存后,将写入 redo log 拆分了成两个步骤:prepare 和 commit,就是常说的两阶段提交。用于保证当有意外情况发生时,数据的一致性。

这里假设下,如果不采用两阶段提交会发生什么?

  1. 先写 redo log 后写 binlog. 假设在写入 redo log 后,MySQL 发生异常重启,此时 binlog 没有写入。在重启后,由于 redolog 已经写入,此时数据库的内容是没有问题的。但此时,如果想要拿 binlog 进行备份或恢复,发现会少了最后一条的更新逻辑,导致数据不一致。
  2. 先写 binlog 后写 redo log. binlog 写入后,MySQL 异常重启,redo log 没有写入。此时重启后,发现 redo log 没有成功写入,认为这个事务无效,而此时 binlog 却多了一条更新语句,拿去恢复后自然数据也是不一致的。

再分析下两阶段提交的过程:

1.在写 redo log prepare 阶段奔溃,时刻 A 的位置。重启后,发现 redo log 没写入,回滚此次事务。

2.如果在写 binlog 时奔溃,重启后,发现 binlog 未被写入,回滚操作。

3.binlog 写完,但在提交 redo log 的 commit 状态时发生 crash

  • 如果 redo log 中事务完整,有了 commit 标识,直接提交。
  • 如果 redo log 中只有完整的 prepare, 判断对应 binlog 是否完整。

完整,提交事务
不完整,回滚事务。


如何判断 binlog 是否完整?

  • statement 格式 binlog,会有 COMMIT; 标识
  • row 格式的 binlog,会有 XID event. 标识
  • 在 5.6 后,还有 binlog-checksum 参数,验证 binlog 正确性。

如何将 redo log 和 binlog 关联表示同一个操作?

结构中有一个共同的数据字段,XID. 在崩溃恢复时,会按顺序扫描 redo log:

  • 如果有 prepare,又有 commit 的 redo log,直接提交。
  • 如果只有 prepare,没有 commit 的 redo log, 拿 XID 去 binlog 找对应的事务做判断。

数据写入后,最终落盘和 redo log 有无关系?

  • 对于正常运行的 instance 来说,内存中页被修改后,和磁盘的数据页不一致,称为脏页。而落盘的过程,是把内存中的数据页写入磁盘。
  • 对于 crash 场景,InnoDB 判断一个数据页是否丢失了更新,会将其读到内存,然后让 redo log 更新内存内容。更新完成后,内存页就变成脏页,然后回到第一种情况的状态。

redo log buffer 和 redo log 的关系?

在一个事务的更新过程中,存在多个 SQL 语句,所以是要写多次日志的。
但在写的过程中,生产的日志要先保存起来,但在 commit 前,不能直接写到 redo log 中。
所以通过内存中 redo log buffer 先存 redo log 的日志。在 commit 时,将 buffer 中的内容写入 redo log.

总结

在文章开始部分,说明了 MySQL 的整体架构分为 Server 层和引擎层,并简要说明了一条语句的执行过程。接着 MySQL 在 5.5 后选用 InnoDB 作为默认的引擎,就是因为比原生的 MyISAM 多了事务以及 crash-safe 的能力。

而 crash-safe 就是由 redo log 实现的。与 redo log 类似的日志文件还有 binlog,是 Server 引擎的日志,用于归档和备份数据。

最后提到了,为了保证数据的一致性,将 redo log 和 binlog 放入相同的事务中,也就是常提到的两阶段提交操作。

以上就是MySQL 整体架构介绍的详细内容,更多关于MySQL 整体架构的资料请关注编程笔记其它相关文章!

原文链接:https://www.cnblogs.com/michael9/p/12497992.html#_label6_0


推荐阅读
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 本文介绍了如何使用python从列表中删除所有的零,并将结果以列表形式输出,同时提供了示例格式。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 本文介绍了Windows操作系统的版本及其特点,包括Windows 7系统的6个版本:Starter、Home Basic、Home Premium、Professional、Enterprise、Ultimate。Windows操作系统是微软公司研发的一套操作系统,具有人机操作性优异、支持的应用软件较多、对硬件支持良好等优点。Windows 7 Starter是功能最少的版本,缺乏Aero特效功能,没有64位支持,最初设计不能同时运行三个以上应用程序。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • java drools5_Java Drools5.1 规则流基础【示例】(中)
    五、规则文件及规则流EduInfoRule.drl:packagemyrules;importsample.Employ;ruleBachelorruleflow-group ... [详细]
author-avatar
周球球J_218
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有