MySQL 体系架构简介

Posted 禅与计算机程序设计艺术

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL 体系架构简介相关的知识,希望对你有一定的参考价值。

前言

mysql是一个典型的C/S架构程序,MySQL Server提供数据库服务,完成客户端的请求和操作,Client负责连接到Server。MySQL和其他关系型数据库不一样的地方在于它的弹性以及可以通过插件形式提供不同种类的存储引擎。

MySQL 体系架构

MySQL逻辑系统架构分为4层:

  • 连接层

  • 应用服务层

  • 存储引擎层

  • 数据存储层

第一层:连接层,所包含的服务并不是MySQL所独有的技术。它们都是服务于C/S程序或者是这些程序所需要的 :连接处理,身份验证,安全性等等。

第二层:服务层 。这是MySQL的核心部分。通常叫做 SQL Layer。在 MySQL据库系统处理底层数据之前的所有工作都是在这一层完成的,包括权限判断, sql解析,行计划优化, query cache 的处理以及所有内置的函数(如日期,时间,数学运算,加密)等等。各个存储引擎提供的功能都集中在这一层,如存储过程,触发器,视 图等。

第三层:引擎层。通常叫做StorEngine Layer ,也就是底层数据存取操作实现部分,由多种存储引擎共同组成。它们负责存储和获取所有存储在MySQL中的数据。就像Linux众多的文件系统 一样。每个存储引擎都有自己的优点和缺陷。服务器是通过存储引擎API来与它们交互的。这个接口隐藏 了各个存储引擎不同的地方。对于查询层尽可能的透明。这个API包含了很多底层的操作。如开始一个事 物,或者取出有特定主键的行。存储引擎不能解析SQL,互相之间也不能通信。仅仅是简单的响应服务器 的请求。

第四层:存储层。主要是将数据存储在运行于裸设备的文件系统之上,并完成与存储引擎的交互。

连接层

应用层是MySQL体系架构的最上层,它可其他client-server架构一样,主要包含如下内容:

连接处理

用户鉴权

安全管理

1. 连接处理当一个客户端向服务端发送连接请求后,MySQL server会从线程池中分配一个线程来和客户端进行连接,以后该客户端的请求都会被分配到该线程上。MySQL Server为了提高性能,提供了线程池,减少了创建线程和释放线程所花费的时间。

2. 用户鉴权 当客户端向MySQL服务端发起连接请求后,MySQL server会对发起连接的用户进行鉴权处理,MySQL鉴权依据是: 用户名,客户端主机地址和用户密码

3. 安全管理 当客户连接到MySQL server后,MySQL server会根据用户的权限来判断用户具体可执行哪些操作。

服务层

该层是MySQL Server的核心层,提供了MySQL Server数据库系统的所有逻辑功能,该层可以分为如下不同的组件:

  • MySQL Management Server & utilities(系统管理)

  • SQL Interface(SQL 接口)

  • SQL Parser(SQL 解析器)

  • Optimizer (查询优化器)

  • Caches & buffers(缓存)

1. MySQL Management Server & utilities(系统管理) 提供了丰富的数据库管理功能,具体如下:

数据库备份和恢复

数据库安全管理,如用户及权限管理

数据库复制管理

数据库集群管理

数据库分区,分库,分表管理

数据库元数据管理

2. SQL Interface(SQL 接口) SQL接口,接收用户的SQL命令并进行处理,得到用户所需要的结果,具体处理功能如下:

Data Manipulation Language (DML).

Data Definition Language (DDL).

存储过程

视图

触发器

3. SQL Parser(SQL 解析器) 解析器的作用主要是解析查询语句,最终生成语法树。首先解析器会对查询语句进行语法分析,如果语句语法有错误,则返回相应的错误信息。语法检查通过后,解析器会查询缓存,如果缓存中有对应的语句,就直接返回结果不进行接下来的优化执行操作。

注:读者会疑问,从缓存中查出来的数据会不会被修改,与真实的数据不一致,这里读者大可放心,因为缓存中数据被修改,会被清出缓存。

4. Optimizer(查询优化器) 优化器的作用主要是对查询语句进行优化,包括选择合适的索引,数据的读取方式。

5. Caches & buffers(缓存) 包括全局和引擎特定的缓存,提高查询的效率。如果查询缓存中有命中的查询结果,则查询语句就可以从缓存中取数据,无须再通过解析和执行。这个缓存机制是由一系列小缓存组成,如表缓存、记录缓存、key缓存、权限缓存等。

存储引擎层

1. 存储引擎 存储引擎是MySQL中具体与文件打交道的子系统,也是MySQL最有特色的地方。MySQL区别于其他数据库的最重要特点是其插件式的表存储引擎。他根据MySQL AB公司提供的文件访问层抽象接口来定制一种文件访问的机制(该机制叫存储引擎)。

2. 物理文件 物理文件包括:redolog、undolog、binlog、errorlog、querylog、slowlog、data、index等。

MySQL存储引擎

InnoDb官方架构图:

InnoDb架构划分为内存结构和磁盘结构

1. 内存结构

1.1 buffer pool(缓冲池)

buffer pool是主存中的一个区域,InnoDB在访问表和索引数据时在这里进行缓存。buffer pool允许直接从内存访问常用数据,从而提高处理速度。在专用服务器上,多达80%的物理内存通常分配给缓冲池。

1.2 change buffer(变更缓冲)

change buffer是一种特殊的数据结构,当二级索引页不在buffer poole中时,它将更改缓存到二级索引页。缓冲的更改(可能由INSERT、UPDATE或DELETE操作(DML)引起)稍后在其他读操作将页面加载到缓冲池时合并。

1.3 adaptive hash index(自适应哈希索引)

自适应哈希索引使InnoDB能够在具有适当的工作负载组合和缓冲池足够内存的系统上执行,更像内存中的数据库,而不会牺牲事务特性或可靠性。自适应哈希索引通过innodb_adaptive_hash_index变量启用,或者在服务器启动时通过——skip-innodb- adaptive_hash -index关闭。

1.4 log buffer(日志缓冲)

log buffer区是存储要写入磁盘日志文件的数据的内存区域。log buffer大小由innodb_log_buffer_size变量定义。默认的大小是16MB。定期将log buffer的内容刷新到磁盘。大log buffer使大事务能够运行,而无需在事务提交之前将redo log数据写入磁盘。因此,如果您有更新、插入或删除许多行的事务,那么增加log buffer的大小可以节省磁盘I/O。

2. 磁盘结构

2.1 tables

2.2 indexes

2.3 tablespace(表空间)

表空间包含了系统表空间、独立表空间、通用表空间、临时表空间以及undo表空间

2.3.1 系统表空间:

a、系统表空间主要是change buffer的存储区域;

b、如果表是在系统表空间中创建的而不是在独立表空间或者通用表空间中创建的,那么系统表空间中也存储创建的表和索引数据;

c、在mysql8.0版本之前,mysql的数据字典也存储在系统表空间之中,不过8.0版本之后,mysql合并了一个事务性数据字典,元数据存储在数据字典中;

d、在MySQL 8.0.20之前,double write buffer存储区域位于InnoDB系统表空间中。从MySQL 8.0.20开始,double write buffer存储区域位于double write文件中;

2.3.2 独立表空间

独立表空间中包含了innoDb表的数据和索引信息,存放在单个的独立表空间文件中

2.3.3 通用表空间

通用表空间是指使用CREATE tablespace语法创建的共享InnoDB表空间

2.3.4 临时表空间

innoDb中使用临时表空间分为session临时表空间和global临时表空间

2.3.5 undo表空间

Undo表空间包含Undo log,Undo log是记录的集合,这些记录包含关于如何撤销事务对聚集索引记录的最新更改的信息。

2.4 double write buffer

double write buffer是一个存储区域,InnoDB在将页面写到InnoDB数据文件中的适当位置之前,在这个存储区域中写入从buffer pool中刷新的页面。如果在页写过程中出现了操作系统、存储子系统或意外的mysqld进程退出,InnoDB可以在崩溃恢复期间从double write buffer中找到一个好的页副本。

虽然数据被写入两次,但double write buffer并不需要两倍的I/O开销或两倍的I/O操作。数据在一个大的顺序块中写入doublewrite缓冲区,通过对操作系统的单个fsync()调用(除非innodb_flush_method设置为O_DIRECT_NO_FSYNC)。

在MySQL 8.0.20之前,double write buffer存储区域位于InnoDB系统表空间中。从MySQL 8.0.20开始,double write buffer存储区域位于double write文件中。

2.5 redo log(重做日志)

redo log是一种基于磁盘的数据结构,在崩溃恢复期间用于纠正不完整事务写入的数据。在正常操作过程中,redo log对SQL语句或低级API调用产生的表数据更改请求进行编码。在意外关闭之前未完成数据文件更新的修改将在初始化期间和接受连接之前自动重播。redo log可用在崩溃恢复。

默认情况下,redo log在物理上由两个名为ib_logfile0和ib_logfile1的文件表示。MySQL以循环的方式写入redo log文件。redo log中的数据按照受影响的记录进行编码;这些数据统称为重做。数据通过redo log的通道由不断增加的LSN值表示。

2.6 undo logs

undo log是与单个读写事务相关联的undo log记录的集合。undo记录包含关于如何撤销事务对聚集索引记录的最新更改的信息。

MySQL 从设计之初,存储引擎就是可插拔的,允许公司或者个人按照自己的需求定义自己的存储引擎(当然,普通的公司或者个人其实是没有这个实力的)。MySQL 自研的使用较广的存储引擎是 MyISAM ,MyISAM 支持表锁,不支持行锁,所以在处理高并发写操作时效率要低一些,另外 MyISAM 也不支持外键(虽然现在实际项目中外键已经用的比较少了)。

虽然 MyISAM 看起来有些简陋,但这并不影响 MySQL 的流行,这就不得不说 MySQL 中另外一个大名鼎鼎的存储引擎 InnoDB 了。

InnoDB 存储引擎是由一家位于芬兰赫尔辛基的名为 Innobase Oy 的公司开发的,InnoDB 存储引擎的历史甚至比 MySQL 还要悠久。可能会有小伙伴决定奇怪,插件竟然比起宿主还要历史悠久?

InnoDB 刚刚开发的时侯,就是作为一个完整的数据库来开发的,因此功能很完备。开发出来之后,创始人是想将这个数据库卖掉的,但是没有找到买家。

后来 MySQL2.0 推出后,这种可插拔的存储引擎吸引了 Innobase Oy 公司创始人 Heikki Tuuri 的注意,在和 MySQL 沟通之后,决定将 InnoDB 作为一个存储引擎引入到 MySQL 中(这就是为什么 InnoDB 比 MySQL 还历史悠久的原因),MySQL 虽然支持 InnoDB ,但是实际上还是主推自家的 MyISAM。

但是 InnoDB 实在太优秀了,最终在 2006 年的时侯,成功吸引到大魔王 Oracle 的注意,大手一挥,就把 InnoDB 收购了。

MySQL 主推自家的 MyISAM ,日子过得也很惨淡,最终在 2008 年被 sun 公司以 10 亿美元拿下,这个操作巩固了 sun 在开源领域的领袖地位,可是一直以来 sun 公司的变现能力都比较弱,最终 sun 自己在 2009 年被 Oracle 收入囊中。

Oracle 收购 sun 之后,InnoDB 和 MySQL 就都成了 Oracle 的产品了,这下整合就变得非常容易了,在后来发布的版本中,InnoDB 慢慢就成为了 MySQL 的默认存储引擎。在最新的 MySQL8 中,元数据表也使用了 InnoDB 作为存储引擎。

InnoDB 存储引擎主要有如下特点:

  1. 支持事务

  2. 支持 4 个级别的事务隔离

  3. 支持多版本读

  4. 支持行级锁

  5. 读写阻塞与事务隔离级别相关

  6. 支持缓存,既能缓存索引,也能缓存数据

  7. 整个表和主键以 Cluster 方式存储,组成一颗平衡树

当然也不是说 InnoDB 一定就是好的,在实际开发中,还是要根据具体的场景来选择到底是使用 InnoDB 还是 MyISAM 。

MyIASM(该引擎在 5.5 前的 MySQL 数据库中为默认存储引擎)特点:

  1. MyISAM 没有提供对数据库事务的支持

  2. 不支持行级锁和外键

  3. 由于 2,导致当执行 INSERT 插入或 UPDATE 更新语句时,即执行写操作需要锁定整个表,所以会导致效率降低

  4. MyISAM 保存了表的行数,当执行 SELECT COUNT(*) FROM TABLE 时,可以直接读取相关值,不用全表扫描,速度快。

两者区别:

  1. MyISAM 是非事务安全的,而 InnoDB 是事务安全的

  2. MyISAM 锁的粒度是表级的,而 InnoDB 支持行级锁

  3. MyISAM 支持全文类型索引,而 InnoDB 在 MySQL5.6 之前不支持全文索引,从 MySQL5.6 之后开始支持 FULLTEXT 索引了(https://dev.mysql.com/doc/refman/5.6/en/mysql-nutshell.html)。

使用场景比较:

  1. 如果要执行大量 select 操作,应该选择 MyISAM

  2. 如果要执行大量 insert 和 update 操作,应该选择 InnoDB

  3. 大尺寸的数据集趋向于选择 InnoDB 引擎,因为它支持事务处理和故障恢复。数据库的大小决定了故障恢复的时间长短,InnoDB 可以利用事务日志进行数据恢复,这会比较快。主键查询在 InnoDB 引擎下也会相当快,不过需要注意的是如果主键太长也会导致性能问题。

相对来说,InnoDB 在互联网公司使用更多一些。

SQL性能优化

一个 SQL 执行的很慢,我们要分两种情况讨论:

偶尔很慢,则有如下原因:

(1)数据库在刷新脏页,例如 redo log 写满了需要同步到磁盘。

(2)执行的时候,遇到锁,如表锁、行锁。

这条 SQL 语句一直执行的很慢,则有如下原因:

(1)没有用上索引:例如该字段没有索引;由于对字段进行运算、函数操作导致无法用索引。

(2)数据库选错了索引。

(3)考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表。

大表数据查询,怎么优化?

(1)优化shema、sql语句+索引;

(2)第二加缓存,memcached, redis;

(3)主从复制,读写分离;

(4)垂直拆分,根据你模块的耦合度,将一个大的系统分为多个小的系统,也就是分布式系统;

(5)水平切分,针对数据量大的表,这一步最麻烦,最能考验技术水平,要选择一个合理的sharding key, 为了有好的查询效率,表结构也要改动,做一定的冗余,应用也要改,sql中尽量带sharding key, 将数据定位到限定的表上去查,而不是扫描全部的表。

SQL SELECT语句执行过程

MySQL 整个查询执行过程,总的来说分为 6 个步骤 : 请求、缓存、SQL解析、优化SQL查询、调用引擎执行,返回结果。

    1、连接:客户端向 MySQL 服务器发送一条查询请求,与connectors交互:连接池认证相关处理。

    2、缓存:服务器首先检查查询缓存,如果命中缓存,则立刻返回存储在缓存中的结果,否则进入下一阶段

    3、解析:服务器进行SQL解析(词法语法)、预处理。

    4、优化:再由优化器生成对应的执行计划。

    5、执行:MySQL 根据执行计划,调用存储引擎的 API来执行查询。

    6、结果:将结果返回给客户端,同时缓存查询结果。

          首先程序的请求会通过mysql的connectors与其进行交互,请求到处后,会暂时存放在连接池(connection pool)中并由处理器(Management Serveices & Utilities)管理。当该请求从等待队列进入到处理队列,管理器会将该请求丢给SQL接口(SQL Interface)。

        SQL接口接收到请求后,它会将请求进行hash处理并与缓存中的结果进行对比,如果完全匹配则通过缓存直接返回处理结果;否则,需要完整的走一趟流程:

        1)由SQL接口丢给后面的解释器(Parser),上面已经说到,解释器会判断SQL语句正确与否,若正确则将其转化为数据结构。

        2)解释器处理完,便来到后面的优化器(Optimizer),它会产生多种执行计划,最终数据库会选择最优化的方案去执行,尽快返会结果。

        3)确定最优执行计划后,SQL语句此时便可以交由存储引擎(Engine)处理,存储引擎将会到后端的存储设备中取得相应的数据,并原路返回给程序。

SQL更新机制和日志记录

基本流程:

查询语句的流程,更新语句也会同样的走一遍。sql= update T set c=c+1 where id=2

1、客户端向 MySQL 服务器发送一条更新请求

2、清除表查询缓存,跟这个有关的查询缓存会失效。这就是一般不建议使用查询缓存的原因。

3、分析器进行 SQL解析(词法和语法分析),分析这是一条更新语句和。

4、优化器生成对应的执行计划,优化器决定使用ID这个索引;

5、执行器负责更新,找到这一行,然后进行更新:

 取数据行: 执行器先找引擎取 ID=2 这一行:  ID 是主键,引擎直接用树搜索找到这一行。如果 ID=2 这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。)

 更新数据: 执行器拿到引擎给的行数据,把这个值加上 1,比如原来是 N,现在就是 N+1,得到新的一行数据,再调用引擎接口写入这行新数据。

更新内存: 引擎将这行新数据更新到内存中,

更新 redo log :同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。然后告知执行器执行完成了,随时可以提交事务。

写入binlog:执行器生成这个操作的 binlog,并把 binlog 写入磁盘。

提交事务: 执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,更新完成。

redo log的实施流程:

提交事务 -> 
日志写入relog log buffer -> 
os buffer -> 
写入磁盘的log file -> 
根据checkpoint更新磁盘中的数据

为了确保每次日志都能写入到事务日志文件中,Redo log写入磁盘时,必须进行一次操作系统fsync操作 (即fsync()系统调用, MySQL是工作在用户空间的,Redo Log buffer也就处于用户空间的内存中),防止redo log只是写入操作系统磁盘缓存中。

重要的日志模块:redo log 和 binlog

前面我们说过,在一个表上有更新的时候,跟这个表有关的查询缓存会失效,所以这条语句就会把表 T 上所有缓存结果都清空。这也就是我们一般不建议使用查询缓存的原因。

接下来,分析器会通过词法和语法解析知道这是一条更新语句。优化器决定要使用 ID 这个索引。然后,执行器负责具体执行,找到这一行,然后更新。

与查询流程不一样的是,更新流程还涉及两个重要的日志模块,它们正是我们今天要讨论的主角:redo log(重做日志)和 binlog(归档日志)。

如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程 IO 成本、查找成本都很高。为了解决这个问题,MySQL 的设计者就用了类似酒店掌柜粉板的思路来提升更新效率(先记录,等不忙时处理)。

redo log固定大小,从头开始写,写到末尾就又回到开头循环写。其中write pos (当前记录的位置)和 checkpoint(当前要擦除的位置) 之间的是“粉板”上还空着的部分,可以用来记录新的操作。如果 write pos 追上 checkpoint,表示“粉板”满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下。

ps:有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为 crash-safe。要理解 crash-safe 这个概念,可以想想我们前面赊账记录的例子。只要赊账记录记在了粉板上或写在了账本上,之后即使掌柜忘记了,比如突然停业几天,恢复生意后依然可以通过账本和粉板上的数据明确赊账账目。

MySQL 整体来看,其实就有两块:

一块是 Server 层,它主要做的是 MySQL 功能层面的事情;

还有一块是引擎层,负责存储相关的具体事宜。 

redo log(重做日志) 是 InnoDB 引擎特有的日志,而 Server 层也有自己的日志,称为 binlog(归档日志)。

ps:因为最开始 MySQL 里并没有 InnoDB 引擎。MySQL 自带的引擎是 MyISAM,但是 MyISAM 没有 crash-safe 的能力,binlog 日志只能用于归档。而 InnoDB 是另一个公司以插件形式引入 MySQL 的,既然只依靠 binlog 是没有 crash-safe 能力的,所以 InnoDB 使用另外一套日志系统——也就是 redo log 来实现 crash-safe 能力。

两种日志模块的区别:

redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。

redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 ID=2 这一行的 c 字段加 1 ”。

redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

将 redo log 的写入拆成了两个步骤:prepare 和 commit,这就是"两阶段提交"。

如果不使用“两阶段提交”,那么数据库的状态就有可能和用它的日志恢复出来的库的状态不一致。redo log 和 binlog 都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致(两阶段提交是跨系统维持数据逻辑一致性时常用的一个方案)。

Redo log机制

InnoDB的redo log 是固定大小,即记录满了以后就从头循环写。

图中展示了一组 4 个文件的 redo log 日志,checkpoint 是当前要擦除的位置,擦除记录前需要先把对应的数据落盘(更新内存页,等待刷脏页)。write pos 到 checkpoint 之间的部分可以用来记录新的操作,如果 write pos 和 checkpoint 相遇,说明 redolog 已满,这个时候数据库停止进行数据库更新语句的执行,转而进行 redo log 日志同步到磁盘中。checkpoint 到 write pos 之间的部分等待落盘(先更新内存页,然后等待刷脏页)。

若可配置2个redo log日志文件.  每个文件的大小是256M,总共记录就是512M;参数如下:

innodb-log-files-in-group      = 2
innodb-log-file-size           = 256M

在innodb将log buffer中的redo log block刷到这些log file中时,会以追加写入的方式循环轮训写入。即先在第一个log file(即ib_logfile0)的尾部追加写,直到满了之后向第二个log file(即ib_logfile1)写。当第二个log file满了会清空一部分第一个log file继续写入。

redo log file的大小对innodb的性能影响非常大,设置的太大,恢复的时候就会时间较长,设置的太小,就会导致在写redo log的时候循环切换redo log file。

redo log日志刷盘策略

参数innodb_flush_log_at_trx_commit可以控制redo log日志刷新到磁盘策略。

innodb_flush_log_at_trx_commit 有3种值:0、1、2,默认为1。但注意,这个变量只是控制commit动作是否刷新log buffer到磁盘。

当设置为1的时候,事务每次提交都会将log buffer中的日志写入os buffer并调用fsync()刷到log file on disk中。这种方式即使系统崩溃也不会丢失任何数据,但是因为每次提交都写入磁盘,IO的性能较差。

当设置为0的时候,事务提交时不会将log buffer中日志写入到os buffer,而是每秒写入os buffer并调用fsync()写入到log file on disk中。也就是说设置为0时是(大约)每秒刷新写入到磁盘中的,当系统崩溃,会丢失1秒钟的数据。

当设置为2的时候,每次提交都仅写入到os buffer,然后是每秒调用fsync()将os buffer中的日志写入到log file on disk。

I/O Master线程这是InnoDB一个在后台运行的主线程。它做的主要工作包括但不限于:刷新日志缓冲,合并插入缓冲,刷新脏页等。Master线程大致分为每秒运行一次的操作和每10秒运行一次的操作。master thread中刷新数据,属于checkpoint的一种。所以如果在master thread在刷新日志的间隙,DB出现故障那么将丢失掉这部分数据。

InnoDB - 关于buffer pool

一、buffer pool是什么?

buffer pool是主存中的一个区域。

二、buffer pool中都有啥?

InnoDB在访问表和索引数据时在这里进行缓存。buffer pool允许直接从内存访问常用数据,从而提高处理速度。在专用服务器上,多达80%的物理内存通常分配给缓冲池。

三、buffer pool的作用与实现?

为了提高大容量读操作的效率,缓冲池被划分为可能包含多行的页。

为了提高缓存管理的效率,缓冲池被实现为页面的链表;很少使用的数据将使用LRU算法的变体从缓存中老化出来。

了解如何利用缓冲池将频繁访问的数据保存在内存中是MySQL调优的一个重要方面。

四、buffer pool LRU算法?

buffer pool使用LRU算法的变体作为列表来管理。当需要空间向buffer pool添加新页时,最近使用最少的页将被排除,并在列表中间添加一个新页。这个中点插入策略将列表视为两个子列表:

~ 在头部,一个最近被访问的新(“年轻”)页面的子列表

~ 在尾部,是最近才访问的旧页面的子列表

官网算法模型:

image.png

该算法将经常使用的页面保存在新的子列表中。旧的子列表包含较少使用的页面;这些页面是被驱逐的候选者。

缺省情况下,算法的操作如下:

缓冲池的3/8用于旧的子列表。

列表的中点是新子列表的尾部与旧子列表的头部相遇的边界。

当InnoDB将一个页读入缓冲池时,它首先将它插入到中间点(旧子列表的头)。可以读取页面,因为它需要用户发起的操作,比如SQL查询,或者作为InnoDB自动执行的预读操作的一部分。

在旧子列表中访问一个页面会使它“年轻”,将其移动到新子列表的头部。如果读取该页是因为用户发起的操作需要它,那么第一次访问将立即发生,该页将被创建为年轻页。如果该页是由于预读操作而读取的,那么第一次访问不会立即发生,而且在该页被逐出之前可能根本不会发生。

当数据库操作时,缓冲池中未被访问的页通过移动到列表的尾部而“老化”。新子列表和旧子列表中的页面随着其他页面的更新而更新。旧子列表中的页面也会随着页面插入到中点而老化。最终,仍未使用的页面到达旧子列表的尾部并被逐出。

默认情况下,查询读取的页面会立即移动到新的子列表中,这意味着它们在缓冲池中停留的时间更长。例如,对于mysqldump操作或没有WHERE子句的SELECT语句执行的表扫描,可以将大量数据带入缓冲池,并排除同等数量的旧数据,即使新数据永远不会再使用。类似地,由预读后台线程加载且只访问一次的页面将被移动到新列表的头部。这些情况可以将经常使用的页面推到旧的子列表中,在那里它们会被逐出。关于优化这种行为的信息,请参见15.8.3.3节“使缓冲池防扫描”和15.8.3.4节“配置InnoDB缓冲池预取(预读取)”。

InnoDB Standard Monitor的输出在BUFFER POOL AND MEMORY部分包含了一些关于BUFFER POOL LRU算法操作的字段。具体操作请参见使用InnoDB标准监视器监控缓冲池。- https://dev.mysql.com/doc/refman/8.0/en/innodb-buffer-pool.html

参考资料

https://www.jianshu.com/p/9c9c68b15063

https://www.51cto.com/article/670426.html

https://blog.csdn.net/hguisu/article/details/7106342

https://www.jianshu.com/p/dfefc8fe30cf

以上是关于MySQL 体系架构简介的主要内容,如果未能解决你的问题,请参考以下文章

A.001.2.Mysql体系架构介绍

MySQL相关简介

Innodb 体系架构

Mysql体系结构

Oracle学习笔记—oracle体系架构及状态(nomountmount和open)简介

Hadoop简介和体系架构