(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:错误显示线程;

 

  

 

 

 

  

 

  

    

 

 

posted @ 2018-09-09 15:15  郭大侠1  阅读(831)  评论(0编辑  收藏  举报