MySQL体系结构

一、体系结构基本理论

1、体系结构是什么?

进程(mysqld)、线程、内存结构、文件结构

mysql数据库是一个单进程多线程的程序。表面上我们只是看到mysqld在工作,然而负责具体功能的是一个一个的线程。

mysqld线程有什么,作用是什么 --> MySQL一些工作机制

除了之间见到的buffer_pool外,内存还有哪些内存结构

mysql数据库文件包含哪些文件,这些文件的功能和内容

这个主要内容目的:熟悉MySQL工作机制、内存结构、文件结构、让我们更好的理解工作原理、能够

实现参数层面的优化。

知识点:

内存 --> buffer pool(包含undo log buffer) + redo log buffer

硬盘 --> 数据块、区、段、表空间、索引

线程

2、MySQL数据库体系结构是分层的:

三层:网络层、SQL层、存储引擎层

二层:service层、存储引擎层

网络层 :其实就是对远程连接的请求进行权限验证。-uroot -hIP --> 验证的是客户端IP以及mysql

用户是都具有权限连接。

权限验证通过之后,就会创建链接(会话、session),并且在数据库端分配用于线程与之

对接。

mysql的用户连接时基于TCP/IP,并且传输层是TCP协议,中间会涉及到TCP连接的握手和

断开,同时数据库层面也会涉及到用户的创建和销毁,而这些操作会影响数据库操作的处

理能力(TPS、QPS),所以在应用端引入了连接池来解决TCP的问题,在数据库端引入

了线程池,来解决线程的创建/销毁的开销。

内容:用于验证链接权限(Mysql.user)、创建会话、分配用户线程

SQL层:数据库及数据表的权限验证、SQL解析、查询缓存

内容:用于解析用户SQL,权限验证,将SQL文本解析为解析树,MySQL优化器对解析树进

行优化然后执行

存储引擎层:指存储引擎,所实现的就是内存和硬盘之间的数据交互。主要关注InnoDB存储引擎

内容:是很多存储引擎,主要是INNOdb,作用是实现内存和硬盘的数据交互。

(1)为什么MySQL会有分层结构 --> 因为是开源的人员,为了给开发人员更多的可以参与的机会,所以将数据库进行了分层结构。当开发人员想要基于MySQL进行二次开发时,往往重点就集中在存储引擎层,开发者可以根据自己的开发需求,开发出符合自己业务场景的存储引擎。只要存储引擎符合mysql的接口协议,那就是兼容的。mysql数据库的存储引擎层有很多存储引擎可以使用。

(2)mysql数据库软件 = 插件的数据库 --> 第三方开发

二、如何提高TPS、QPS及发送消息占用时间(网络层)

1、mysql数据库连接和发送消息传递图

用户线程:当web服务器向数据库服务器发送了一个select查询请求的时候,就会生成一个用户线程,来负责处理这个请求。

权限验证:当权限验证通过了,意思就是user用户表里面允许你登录了之后,就会分配一个用户线程来处理事务了。

MySQL体系结构_第1张图片

 

2、因TCP/IP的握手断开机制占用过多时间解决方案

TCP/IP :mysql都是tcp协议,所以是都三次握手和四次断开

TPS:每秒事务数

QPS:每秒查询数

(1)一个请求的过程:

现在应用服务器需要进行一个查询操作 select * from mysql.user;

首先就是应用服务器和数据库服务器之间要建立网络连接(会话),而会话都是基于TCP/IP协议的

TCP/IP网络连接的建立:三次握手 发送数据 四次断开 (默认只能处理一个请求)

三次握手 发送数据 四次断开 发送8次

三次握手 返回结果 四次断开 发送8次

1000个请求,1s内数据库需要处理1000次的请求,那么应用服务器和数据库服务器需要处理16000次的传输,实际上有效的只有2000次。所以就会有14000次的浪费时间,所以会导致额外的TCP的网络代价会很大,会导致性能比较差。

就是因为TCP中有这握手和断开的机制,也就导致了网络传输性能的下降。

(2)连接池的作用

所以:为了减小应用服务器和数据库服务器的连接开销,就是应用服务器和数据库服务器tcp连接一直

进行三次握手和四次断开的开销,有了 --> 连接池。连接池往往是在应用服务器上实现的,

连接池目的:就是为了维持TCP连接,如上图,应用服务器和数据库服务器中建立一个连接池,这个连接池是一直不断开的,当应用服务器需要去数据库服务器上找数据库的时候,就直接从连接池中拿出来一个连接,进行通讯发送数据,发送返回结果完成后,连接池的连接也不断开,这样的话三次握手和四次断开就省了,不在等待握手和断开时间,就会明显提升速度。

应用端连接池能够维持mysql会话的存在。

3、因线程创建注销占用时间解决方案

当客户端连接到数据库时,mysql就会创建一个用户线程与之对应,当会话断开时,该用户线程被注销。

两个操作:创建线程、注销线程 --> 这两个都会占用时间

解决方案:就有了线程池的概念,数据库建了线程池,当会话建立线程时,直接分配线程即可,避免创建线程、注销占用时间

注意:mysql社区版 --> 没有线程池功能

mysql企业版、Percona-service中有线程池功能

4、使用连接池/线程池 --> 目的:为了提高平TPS、QPS提高数据库服务器的并发能力,提升性能

三、业务场景(网络层)

数据库是从如下场景下工作的:OLTP、OLAP

1、OLTP --> 在线事务系统(一般电商行业比较多)

特点:并发量很高

TPS、QPS比较高

处理的请求都比较简单,都是一些简单的查询

对应的查询效率及安全性比较高

2、OLAP --> 在线分析系统(一般是用户行为分析)

特点:数据量很大

TPS、QPS比较低

处理的查询逻辑往往非常复杂

对查询的效率及安全性往往不是很高

四、SQL层

1、sql层的作用 --> 由sql层处理应用端发送过来的SQL语句

sql层的实现是数据库性能的体现,不同的数据库性能不同,对大部分因素是由SQL决定的

2、主要的sql层内容:

(1)权限验证 *.*

(2)SQL解析 --> SQL解析器 --> SQL文本(select * from mysql.user) --> 解析树

(3)优化器 --> 根据数据库的统计信息,对SQL进行优化 --> SQL改写,执行计划

(4)查询缓存:缓存查询语句的查询结果(并不是缓存SQL语句,而是将结果进行缓存)

优点:当同样的查询语句请求时,MYSQL直接将查询结果反馈给应用。(SQL的解析和内存

于硬盘的数据交互可省略),可以相同的语句不进行解析直接查询结果。

而内存空间是有限的,在内存中能缓存的查询结果是优先的。

查询缓存这种功能,因为不同的查询语句,缓存的结果就不能用了,所以往往查询缓存更新的特别频繁,增加内存的处理压力,吃太多的内存。

结论:查询缓存不能用,musql8.0版本取消了

查看参数:show variables;

show variables like '%query%' ; --> 和查询相关的参数

query_cache_size | 1048576 --> 定义查询缓存区空间大小

query_cache_type | OFF --> 查询缓存功能开启/关闭

参数分类:在线参数(支持在线修改的参数)、只读参数(不允许在线修改的参数)

在线意思:mysql运行期间的修改

修改参数:在线参数修改:

set global 参数名称 = 参数值 --> 对所有会话生效,当前实例生效

set session 参数名称 = 参数值 --> 对当前会话的实例生效,session可以省略

例如:set global max_connectios=3000

注意:这种在线参数的修改都是临时生效的,哪怕是global如果实例关闭后重启也会失效,如果需要持久修改方法:set global(保证当前是有效) + 参数文件(保证数据库实例重启后有效)

只读参数修改:

将数据库关闭后,将对应参数写入参数文件my.conf,之后重启数据库

四、存储引擎层

(1)存储引擎中会有很多存储引擎

存储引擎作用:存储引擎就是负责管理内存和硬盘的数据交换。

分层结构的优势:更多的开发人员能够参与到开发过程中去,可以开发很多适用于不同场景的存储引擎,最终以插件的形式集成在mysql当中。

分层节后的缺点:但是存储引擎层和SQL层会有数据交换的过程,劣势就在于存储引擎层和SQL层交互时,会有比较大的性能损耗。

向一些商业数据库,如oracle、sqlservice是一体化设计,所以在这个层面上没有性能损耗的问题。但是也是因为分层结构,导致很多人参与到了MYSQL开发中,很多中存储引擎。

rokedb、inforbridge、ariadb --> 第三方存储引擎

Innodb、MyISAM、Memory、BlockHole、ndb等 --> MySQL自带的存储引擎

目前还是以innodb为主,mysql主要还是以INNODB为主。

在创建数据表时候,可以指定存储引擎,通过engine来定义。就是mysql默认的存储引擎,这个默认的是什么存储引擎,是在con.cnf来定义的。创建数据表的时候也可以手动指定存储引擎。

(2)操作

show engines --> 查看数据库中有哪些存储引擎

show plugins --> 查看插件

创建数据库:create database 库名称

创建数据表:create table 表名 (字段名)

例如:create table ctl (id int not null,name varchar(20),phone int(11))

show create table 表名 --> 查看建表语句

五、线程

1、进程和线程

进程 --> 运行的程序称之为进程。将本来存放在硬盘中的代码运行到内存空间中,称之为进程。进程

中除了有程序代码,还包括程序运行占用的内存空间,以及各种网络空间、用户空间等。但

是进程中真正工作的就是部分代码。

线程 --> 进程中真正工作的就是部分代码,一个程序由大量的代码构成,不同的代码功能不同,在内

存中不同的代码段实际上是串行执行的,这种一段一段执行的代码我们就叫执行序,也叫线

程。不同的线程都在运行,负责不同的功能模块。在多线程变成模型中,设计出的程序包含

多个线程,执行不同的功能。后来出现了多核,就是单颗CPU集成了多个计算核心,4核,

不同的计算核心可以处理不同的任务。多核的出现大大提升处理多进程的性能。

进程 = 线程 + 运行环境

所以真正干活的是线程,oracle是一个多进程单线程的数据库,但是oracle中不同的进程中有不同的线程负责不同的功能,但是oracle中很少去提线程的概念。

物理CPU:CPU芯片个数

逻辑CPU数:物理CPU数量 x 单颗CPU核心数

现在单颗CPU由集成了多个计算核心,又成为比如4核。不同的计算核心可以处理不同的任务。

1个进程 --> 1个逻辑CPU

MySQL就是一个单进程多线程的编程架构 --> MySQL对外表现为单进程,但是内部包含很多不同功

能的线程。线程都是串行执行的。不同的线程功能不同

在linux2.6版本后,支持一个进程中的不同线程使用不同的逻辑CPU,现在,多进程的编程架构和单进程多线程的架构没有了明显的区别。

有时,有人写喜欢将线程称之为轻量级进程。但是有些人会任务轻量级进程是内核进程,线程就是线程。

2、MysQL中的线程

MySQL线程四大类:log thread、read thread、write thread、insert buffer thread

(1)read thread线程和write thread线程

进程的功能 --> 其实就是各个线程的功能加起来 + 线程的运行环境、内存空间

线程的IO --> 线程是存在于内存中的,所以是站在内存的角度,硬盘到内存就输入,内存到硬盘叫

输出。

I input 硬盘到内存 --> file 到 buffer pool --> read thread线程(加载数据到buffer pool)

O output 内存到硬盘 --> buffer pool 到 file --> write thread线程 (刷脏、数据页落盘)

刷脏时往往落盘的数据块是比较多的(200-20000),从硬盘加载数据块到buffer pool

IO线程往往有很多,默认情况下,read thread线程和write thread线程各4个。如果IO比较多,可以调整为各8个。

对应参数:InnDB_read_io_threads --> 现在版本都默认8个线程。

InnDB_write_io_threads --> 现在版本都默认8个线程。

innodb_in_capacity --> 该参数决定了每次刷脏的数据页数量,默认是200页。如果

磁盘性能好,是越大越好。

innodb_in_capacity_max --> 每次刷脏的数据页最大数量,一般只看上面一个,不看这个

innodb_page_cleaners --> 可设置多个page cleaner线程提高脏页刷新效率。

innidb_file_per_table --> 每个表都有自己独立的表空间,每个表的数据和索引

如何设置innodb_in_capacity 这个值:

200 --> SAS机械磁盘/SATA机械磁盘 --> 单磁盘

2000 --> SAS机械磁盘/SATA机械磁盘 --> 做RAID10(硬RAID)

5000 --> SATA 固态硬盘

20000 --> PcIE 固态硬盘

查看线程:show variables like ‘%io_threads%’ --> 查看线程参数

show engine innoDB status\G; --> 查看线程状态

(2)redo log thread

redo log thread --> redo log落盘,控制redo log buffer落盘具体有redo log thread来完成

当数据页发生修改 --> 记录redo log --> redo log buffer 通过 redo log thread 落盘到 redo log file中

(3)master thread

master thread --> 后台有两种循环,一种是1s循环,一种是10s循环,再循环内可以调用其他线程

进行相关操作。master thread优先级别最高。

(4)insert buffer thread

insert buffer thread --> 合并insert buffer中的索引和辅助索引

(5)user thread

user threa --> 当一个用户连接上来之后建立会话,就会有user thread线程。

(6)purge thread

purge thread --> 清除行记录,对数据页行记录的真正删除操作和删除undo log

功能:1.delete标记为删除之后commit提交之后,真正删除记录 2.删除undo log

注意1:数据库执行了delete操作后,数据库是有很多个会话同时连接的,删除数据这条数据被标记删除之后还没有进行commit提交,在本会话中在进行select查询就查不到了,但是别的会话查看被删除的记录是还可以查询到的。

delete操作和标记删除操作时同时发生的 --> 同步操作

delete操作和purge操作(真正清数据清空间)不是同时发生的 --> 异步操作

总结:删除的记录最后会被purge线程回收,就是commit提交之后会删除数据页中的行记录,清空空间,purge还会检测记录上是否有其他事物在引用undo,如果没有,就可以删除。

理解:进入了delete操作但未commit时,删除的数据会在数据页中打上标记,并记录undo,undo其实就是在buffer pool中的一块空间,用处是将需要删除但是未commit的数据整个行记录放入到undo中,防止进行rollback操作和当另外会话查询的这条delete但是未commit的数据时查的是undo的数据,当这条数据commit后,会真正删除数据页中的数据了,purge还会检测记录上是否有其他的事物在引用undo,如果没有就可以删除。

参数:innodb_purge_threads=4 --> 处理并发的,就是有几个线程在操作,delete update很频繁的

话,可以设置为8。

(7)page cleaner

page cleaner --> 用于刷脏

脏页 --> FLU list刷新链表,在FLU list中存在buffer pool中的所有脏页,我们刷脏选择的脏页就从FLU

list获取。

基本概念:如下图

MySQL体系结构_第2张图片 

page cleaner 和write thread区别:

write thread是只是写线程,从内存到硬盘,但是他找不到脏页,需要有人把脏页拿给他,之后write thread来把内存数据写到硬盘上。中间需要有人参与,将flu list中的脏页交给write thread来刷新到硬盘中。5.6版本开始,page_cleaner线程负责,但是默认只有一个page_cleaner,按照默认来的话,一个page_cleaner线程负责提交脏页地址给4个write thread。5.7版本中为了他提高刷脏效率,引入了多个page cleaner。参数是:innodb_page_cleaners

你可能感兴趣的:(mysql,数据库,服务器)