(1.1)学习笔记之mysql体系结构(内存、进程、线程)
关键词:mysql体系结构
参考:https://www.cnblogs.com/zhoubaojian/articles/7866292.html
一、mysql体系架构概述
1.1 mysql体系结构概述
(1)mysql是单进程、多线程的架构,oracle是多进程的架构(windows也是单进程,通过windows虚拟机)。
单进程、多线程:上下文切换代价比较小,CPU消耗比较少。
多进程:并发比较好,上下文切换代价比较大。
(2)mysql存储引擎是可插拔的;什么是存储引擎?存储引擎就是对数据库进行CRUD等相关操作的。存储引擎的对象就是表。
(3)体系结构自上而下大概分为4部分
【1】应用程序连接器:为各类应用程序提供连接方式
【2】连接池:缓存各个应用程序的连接信息,以便不需要每次都去数据库初始化。
【3】SQL层:
企业管理服务于工具(management service & untilities):用于管理Mysql,用于协助使用mysql;包括备份、恢复、复制、权限等等
SQL接口(SQL Interface):用于提供结构来接收外部传输的SQL操作;包括ddl、dml、sp、view、triggers、etc等等
剖析器(parser):用于分析事物,分析语法是否正确
优化器(optimizer):用于优化SQL,进行选择-投影-连接行程结果。
缓存器与缓冲池(buffer & cache):用于缓存磁盘IO数据,缓存CPU与内存协调数据。
【4】存储层
存储引擎(可热拔插):决定数据存储的方式和形式
磁盘存储:直接落地到磁盘的各类文件与数据。
1.2 mysql实例与数据库的概念
(1)mysql 1个实例对应多个1个数据库(整体概念,说的是数据文件而不是create database这个);磁盘上的文件叫数据库,内存和进程叫实例。
(2)oracle 可以1个数据库(整体概念)对应多个实例(即RAC);
(3)数据库实例来操作数据库数据库。
二、mysql InnoDB体系概念
(1)mysql存储引擎就可以看做是数据库
(2)内存加进程可以看做是实例
红线框起来的叫实例,蓝色框起来的叫数据库,其关系为1比1;
mysql5.6 InnoDB 内存系列(Buffer Pool、additional memory pool、redo log buffer pool)
对应这个参数;下面来详解一下;
(3)buffer pool:
(3.1)index page/data page缓冲
就是块数据以及脏数据缓存。
在磁盘中叫块(block),在内存中叫Page,其实是一个概念,Mysql 默认是16K一个块/页。(帧)
本模块主要放聚集索引组织的数据以及脏数据,注意这里也包含聚集索引的叶子节点,也称之为以聚集索引的方式缓存表数据。
(3.2)data dictionary缓冲
数据字典,物理上数据信息存放在mysql根目录下的iblog目录下的ibdata1/ibdata2。
本模块主要是在DDL操作时做内存数据字典缓冲。
(3.3)lock info缓冲
mysql中,行锁信息会放在lock info缓冲里,行锁信息从这里找。
但大事务、大数据量,行锁达到一定程度会自动升级为表锁。
(3.4)undo page缓冲
物理上数据信息存放在mysql根目录下的iblog目录下的ibdata1/ibdata2。
每次做操作的时候,会把修改、增加、删除的前镜像放入Undo page,以便事务回滚
(3.5)insert buffer page缓冲(change buffer)
缓存普通索引/非聚集、非唯一索引。(就是所有缓存)
在非聚集索引中,如果2个值相差很大,如(1,123456),(2,654321)在磁盘上的存放位置就会相隔较远,我们的hdd磁盘的随机读写比较差,很影响效率。
这个缓冲解决了这个问题,使用space_id和Page_no +索引值,存放到该缓冲。使用完之后,然后merge合并,插入到磁盘中,减少磁盘IO提高效率。
(3.6)adaptive hash index缓冲
查找算法:
(1)链表遍历 O(N)
(2)二分查找 Log(N)
(3)B-TREE查找 Log(N)
(4)hash查找Log(1)
这一块就是用来缓冲Hash索引。
(4)additional memory pool
附加内存池,随着buffer pool的大小而需要对应增减。单位是byte,默认是8M
(5)redo log buffer
其实就是日志缓存池,【1】一般commit就会提交到磁盘日志文件上去 【2】通过设置每1秒刷新 【3】log write(redo log buffer满一半,即1/2))
物理上存放如下;
(6)binlog buffer
主要用来缓存各种数据变更操作所产生的二进制信息。二进制日志会先写入binlog buffer ,然后再写入到磁盘log file。
与redo log buffer的区别;
【1】从类别来说: Binlog buffer包含innodb与myisam引擎,而redo log buffer只在Innodb里面;
【2】从记录方式: 二进制日志:记录日志的具体操作内容,是逻辑日志 重做日志:记录每个页的更改的物理情况;
【3】从时间上说: 二进制日志:只在事务完成后进行写入,只写磁盘一次,无论这时事务有多大 重做日志:在事务进行中,就不断有重做日志条目(redo entry)写入重做日志文件;
(7)double write Buffer
(是innodb表空间ibdata中一块连续的128page=2M的存储空间,它的作用是处理产生Partial write时候的data recovery)
以一个insert 为例。步骤如下
【1】从磁盘读取page到index page(也就是把数据都缓存到内存),这个过程是同步的。
【2】在内存中插入数据,然后再准备写回磁盘,这个过程是异步的。
问:插入在内存中该页为16K,脏页刷新写入磁盘写到一半的时候也就是8K的时候突然出问题了,后续写入失败了。这个时候咋办?
答:这个时候实际数据页坏了,redo恢复不了。因为每个页头部和尾部都有个checksum校验和,当你写到一半的时候,页是有问题的(因为头部和尾部的checksum校验和不一致),mysql会把页设置为损坏状态。redo去重做的时候,发现该页是损坏的(checksum头尾不一致)。redo无法恢复,因为redo里面没有保留数据页完整的镜像,只是保留了这个page里面修改的某条记录。所以当page不完整的时候,redo没办法去修改。
所以为了解决这个问题,mysql里面有了double write。double write怎么做到的呢,步骤如下;
【3】脏数据插入磁盘过程:首先会把脏数据放入double write里面
【4】double write会把数据写入到 sys tablespace中的double write segment(即表空间中的专属双写段中),其实就是写到了上面说过多次的ibdata1/ibdata2中(这个步骤其实已经把数据持久化到磁盘上了)。如果从double write内存中写入到double write segment过程中出了问题,那么先丢弃掉double write segment中的本次已写数据。然后double write会重新写入一遍,直到数据写入到double write segment中去为止。
【5】然后再从double write segment 中写入到user tablespace中的正式数据文件中去。如果这个过程中发生写坏了的情况,那么double write segment中已经存在持久化的完整的数据页信息,会重新写一份到正式数据文件中去。
那么内存到这里就基本学习完了。下面继续学习线程。
mysql InnoDB 线程系列
1.查看
查看mysql进程与线程
ps -ef |grep 3306
#效果如下
#看图中 进程号为3530,那么我们要查看进程中的所有线程命令如下
pstack 3530
#如下图,我这里一共28个线程
深入讲解所有线程
(1)user threads :用户连接线程
(2)full text seach optimize thread:全文搜索线程
(3)rollback clean thread:回滚线程
(4)recv write thread:恢复线程
(5)redo log thread:刷日志线程,当内存中的redo log buffer有事务commit的时候,会刷日志数据到磁盘。或者当redo log buffer超过其buffer阈值 1/2的时候,也会刷日志数据到磁盘。每1s也会刷。
(6)write thread:配合double write去写,异步写入,我这里设置的是10个。
(7)read thread:读线程,这里为预读。我这里线程数为4
(8)purge thread:清除线程,当undo buffer比较大的时候,专门用这个线程来清除undo buffer里面的数据;让undo可以重用。如下图:我设置的每次purge 300个页,线程为1;默认是10S刷新一次(在undo buffer没有使用的情况下),而且,undo buffer一定是要比脏数据提前存到磁盘的。。。
这样就不会反复写入,把undo 文件撑得很大。
(9)page cleaner thread:刷脏块/index page线程(使用LRU算法)
内存分为三大Page:
【1】free page; 【2】clean page; 【3】dirty page;
(10)master thread:刷insert buffer page。使用merge来合并insert buffer page里面的数据,然后一次性的去写入到磁盘;
(11)buffer dump thread:保留/启用预热数据
我们启用一下这个线程,然后看看其作用。
关闭Mysql之后,热数据(内存数据)会放到这里来
然后这个文件里面存的热块内容是:space_id和page_no
以前没这个参数的时候,我们都是通过select count(*) from table 来预热某个表。
(12)monitor thread:监听线程;
(13)dictionary stats thread:字典状态datas dictionary线程;
(14)lock timeout thread:锁超时线程;
(15)error monltor thread:错误显示线程;