Mysql启动过程

1,559 阅读10分钟
    1. 命令行启动mysql,初始化模块结果控制权:
  • 读取配置文件,文件路径 etc/my.cnf文件 如果多个相同配置参数,去最后一个
  • 链接管理器:链接的时候会通过tcp/ip协议检查权限,校验user表
    1. 线程管理器
    1. 调用用户验证模块:
    1. 命令调度器/查询器
    1. 查询高速缓存
    1. 缓存未命中->解析器(parser)
    1. 访问控制模块
    1. 表管理器
    1. 抽象存储引擎执行sql
    1. 日志记录模块
    1. 完成任务,返回连接线程

InnoDB由Innobase Oy公司所开发,2006年五月时由Oracle并购。 innodb特点: 行锁 外键 事务

1、插入缓冲(insert buffer)的原理:(提高写性能) 非聚集索引写性能问题 为了阐述非聚集索引写性能问题,我们先来看一个例子: mysql>create table t (

       id int auto_increment, 

       name varchar(30), 

       primary key (id)); 

我们创建了一个表,表的主键是id,id列式自增长的,即当执行插入操作时,id列会自动增长,页中行记录按id顺序存放,不需要随机读取其它页的数据。因此,在这样的情况下(即聚集索引),插入操作效率很高。 但是,在大部分应用中,很少出现表中只有一个聚集索引的情况,更多情况下,表上会有多个非聚集的secondary index (辅助索引)。比如,对于上一张表t,业务上还需要按非唯一的name字段查找,则表定义改为:

mysql>create table t (

       id int auto_increment, 

       name varchar(30), 

       primary key (id), 

       key (name)); 

这时,除了主键聚合索引外,还产生了一个name列的辅助索引,对于该非聚集索引来说,叶子节点的插入不再有序,这时就需要离散访问非聚集索引页,插入性能变低。

插入缓冲技术机制 为了解决这个问题,InnoDB设计出了插入缓冲技术,对于非聚集类索引的插入和更新操作,不是每一次都直接插入到索引页中,而是先插入到内存中。具体做法是:如果该索引页在缓冲池中,直接插入;否则,先将其放入插入缓冲区中,再以一定的频率和索引页合并,这时,就可以将同一个索引页中的多个插入合并到一个IO操作中,大大提高写性能。回忆一下在《 MySQL - 浅谈InnoDB存储引擎》中提到的master thread主循环其中的一项工作就是每秒中合并插入缓冲(可能)。 这个设计思路和HBase中的LSM树有相似之处,都是通过先在内存中修改,到达一定量后,再和磁盘中的数据合并,目的都是为了提高写性能,具体可参考《HBase LSM树》,这又再一次说明,学到最后,技术都是相通的。 插入缓冲的启用需要满足一下两个条件:

1)索引是辅助索引(secondary index) 2)索引不适合唯一的 如果辅助索引是唯一的,就不能使用该技术,原因很简单,因为如果这样做,整个索引数据被切分为2部分,无法保证唯一性。   对于非聚集索引的插入和更新,不是每一次直接插入索引页中,而是首先判断插入的非聚集索引页是否在缓冲池中,如果在,则直接插入,否则,先放入一个插入缓冲区中。好似欺骗数据库这个非聚集的索引已经插入到叶子节点了,然后再以一定的频率执行插入缓冲和非聚集索引页子节点的合并操作,这时通常能将多个插入合并到一个操作中,这就大大提高了对非聚集索引执行插入和修改操作的性能。 2、两次写(double write)(提高写可靠性) 部分写失效 想象这么一个场景,当数据库正在从内存向磁盘写一个数据页时,数据库宕机,从而导致这个页只写了部分数据,这就是部分写失效,它会导致数据丢失。这时是无法通过重做日志恢复的,因为重做日志记录的是对页的物理修改,如果页本身已经损坏,重做日志也无能为力 从上面分析我们知道,在部分写失效的情况下,我们在应用重做日志之前,需要原始页的一个副本,两次写就是为了解决这个问题,下面是它的原理图:   两次写给innodb带来的是可靠性,主要用来解决部分写失败(partial page write)。doublewrite有两部分组成,一部分是内存中的doublewrite buffer,大小为2M,另外一部分就是物理磁盘上的共享表空间中连续的128个页,即两个区,大小同样为2M。当缓冲池的胀业刷新时,并不直接写硬 盘,而是通过memcpy函数将脏页先拷贝到内存中的doublewrite buffer,之后通过doublewrite buffer再分两次写,每次写入1M到共享表空间的物理磁盘上,然后马上调用fsync函数,同步磁盘。如下图所示

两次写需要额外添加两个部分: 1)内存中的两次写缓冲(doublewrite buffer),大小为2MB 2)磁盘上共享表空间中连续的128页,大小也为2MB

其原理是这样的: 1)当刷新缓冲池脏页时,并不直接写到数据文件中,而是先拷贝至内存中的两次写缓冲区。 2)接着从两次写缓冲区分两次写入磁盘共享表空间中,每次写入1MB 3)待第2步完成后,再将两次写缓冲区写入数据文件

这样就可以解决上文提到的部分写失效的问题,因为在磁盘共享表空间中已有数据页副本拷贝,如果数据库在页写入数据文件的过程中宕机,在实例恢复时,可以从共享表空间中找到该页副本,将其拷贝覆盖原有的数据页,再应用重做日志即可。 其中第2步是额外的性能开销,但由于磁盘共享表空间是连续的,因此开销不是很大。可以通过参数skip_innodb_doublewrite禁用两次写功能,默认是开启的,强烈建议开启该功能。 slave上可以通过设置skip_innodb_doublewrite参数关闭两次写功能来提高性能,但是master上一定要开启此功能,保证数据 安全。 3、自适应哈希索引(adaptive hash index)   由于innodb不支持hash索引,但是在某些情况下hash索引的效率很高,于是出现了 adaptive hash index功能,innodb存储引擎会监控对表上索引的查找,如果观察到建立hash索引可以提高性能的时候,则自动建立hash索引。可以通过 show engine innodb status\G来查看自适应哈西索引的使用情况。可以使用innodb_adaptive_hash_index来禁用和启用hash索引,默认开启。 哈希索引是一种非常快的等值查找方法(注意:必须是等值,哈希索引对非等值查找方法无能为力),它查找的时间复杂度为常量,InnoDB采用自适用哈希索引技术,它会实时监控表上索引的使用情况,如果认为建立哈希索引可以提高查询效率,则自动在内存中的“自适应哈希索引缓冲区”(详见《MySQL - 浅谈InnoDB体系架构》中内存构造)建立哈希索引。 之所以该技术称为“自适应”是因为完全由InnoDB自己决定,不需要DBA人为干预。它是通过缓冲池中的B+树构造而来,且不需要对整个表建立哈希索引,因此它的数据非常快。 InnoDB官方文档显示,启用自适应哈希索引后,读和写性能可以提高2倍,对于辅助索引的连接操作,性能可以提高5被,因此默认情况下为开启,我们可以通过参数innodb_adaptive_hash_index来禁用此特性。

四种隔离级别说明 隔离级别 脏读(Dirty Read) 不可重复读(NonRepeatable Read) 幻读(Phantom Read) 未提交读(Read uncommitted) 可能 可能 可能 已提交读(Read committed) 不可能 可能 可能 可重复读(Repeatable read) 不可能 不可能 可能 可串行化(SERIALIZABLE) 不可能 不可能 不可能 如何防止幻想读问题:间隙锁 www.mamicode.com/info-detail…

blog.csdn.net/tangkund321…

后台线程

默认情况下,InnoDB的后台线程有7个 —— 4个IO thread, 1个master thread, 1个lock monitor thread, 一个error monitor thread

内存

InnoDB的内存主要有以下几个部分组成:缓冲池 (buffer pool)、重做日志缓冲池(redo log buffer)以及额外的内存池(additional memory pool),如下图所示:

其中缓冲池占最大块内存,用来缓存各自数据,数据文件按页(每页16K)读取到缓冲池,按最近最少使用算法(LRU)保留缓存数据。 缓冲池缓冲的数据类型有:数据页、索引页、插入缓冲、自适应哈希索引、锁信息、数据字典信息等,其中数据页和索引页占了绝大部分内存。

日志缓冲将重做日志信息先放入这个缓冲区,然后按一定频率(默认为1s)将其刷新至重做日志文件。

Master 后台线程

InnoDB的主要工作都是在一个单独的Master线程里完成的。Master线程的优先级最高,它主要分为以下几个循环:主循环(loop)、后台循环(background loop)、刷新循环(flush loop)、暂停循环(suspend loop)。

先来看看主循环,下面是它的伪代码: [plain] view plain copy

  1. void master_thread() (
  2. loop:
  3. for (int i =0; i <10; i++){
  4. do thing once per second  
    
  5. sleep 1 second if necessary  
    
  6. }
  7. do things once per ten seconds
  8. goto loop;
  9. }

其中每秒一次的操作包括: 刷新日志缓冲区(总是) 合并插入缓冲(可能) 至多刷新100个脏数据页(可能) 如果没有当前用户活动,切换至background loop (可能) 和Oracle类似,即使事务未提交,也会每秒刷新重做日志缓冲区。

其中每10秒一次的操作包括: 合并至多5个插入缓冲(总是) 刷新日志缓冲(总是) 刷新100个或10个脏页到磁盘(总是) 产生一个检查点(总是) 删除无用Undo 页 (总是)

接着来看后台循环,若当前没有用户活动或数据库关闭时,会切换至该循环执行以下操作: 删除无用的undo页(总是) 合并20个插入缓冲(总是) 跳回到主循环(总是) 不断刷新100个页,直到符合条件跳转到flush loop(可能) 如果flush loop中也没有什么事情可做,边切换到suspend loop,将master线程挂起。

Innodb引擎内存:

  1. buffer pool 参数(innodb_buffer_pool_size)
  2. redo log bugger 参数(innodb_log_buffer_pool_size)
  3. additional member pool 参数(innodb_additionnal_mem_pool_size) 存储:帧缓冲(frame buffer),缓冲控制对象,LRU,锁,等待等信息。

innodb plugin开始 脏页刷新比例由90%调整到了75%,google测试最优值是80%。

表空间组成:

  1. 段:数据段,索引段,回滚段。
  2. 区:
  3. 页 page innodb物理存储: 数据,索引,表的内部数据字典存放在.ibd 表结构定义文件存放在.frm

mysql varchar的最大长度是2的16次方=65535,因为2个字节16位。

innodb存储引擎里,B+tree本身并不记录具体一行数据的位置,只记录该记录所在页,然后通过Page Dictionary二分查找,Page被加载到内存里,时间复杂度比较低。时间几乎可以忽略。

问题: 所谓的存储引擎架构标准是什么?查看官方文档第16章 innodb插入缓存的作用。

Wiki编写内容: innodb行锁源代码,原理。