InnoDB运行时内存体系架构

InnoDB引擎在运行期间,实际上就是一个用户进程来做为客户与磁盘之间交互的一个通道。而在内存上,InnoDB引擎实际上分为两大块区域:后台线程内存池算法

后台线程

InnoDB是多线程模型,因此在运行过程当中有多个不一样的后台线程,分别执行不一样的任务。sql

Master Thread

Master Thread是全部后台线程中所核心的一个,主要负责脏页的刷新,插入缓冲的合并,Undo log的回收(1.1版本以前)等核心任务缓存

IO Thread

在InnoDB中大量使用了AIO来提高IO效率,而其中的IO线程能够分为四种:write,read,insert,log IO Thread,分别负责对这四种IO操做进行发起和回调。在1.0及其以前的版本中,这四种线程各有一种。而在以后的版本,write金和read线程数就增长到各位4个多线程

Purge Thread

InnoDB实现了事务机制,而事务的一些基础功能如回滚,是经过每一个事务的Undo log来实现的,也就是说,当事务提交以后,其内部造成的版本链就没有存在的意义了,因此此时Purge Thread就负责回收这些Undo log(其实在1.1版本以前,这个操做是由Master Thread去作的,后来就加入Purge Thread用来减轻Master Thread的负担)性能

内存

缓冲池

缓冲池其实包含了挺多东西的:操作系统

主要其实就是三个:数据页,插入缓冲和自适应哈希索引 其实在1.0以后的版本之中,InnoDB在运行时期有多个缓冲池实例,数据页哈希到不一样缓冲池上进行存放。

数据页

通常来讲为了协调CPU和磁盘处理速度上数量级的差距,操做系统都会有设置缓存的作法, 把屡次IO合并变成一次IO,从而提高效率。InnoDB也不例外。InnoDB不会对每一次修改操做都进行一次磁盘IO,那未免也太慢了。因此在内存上,InnoDB维护了一个数据页区域,对该数据页的修改,都会先在内存上找到该数据页(若是内存中没有怎么办?稍后再说),这个数据页修改以后,就变成了一个脏页,等待合适的时机,再会把这个脏页刷新回磁盘中。所以,为了防止存在内存的这部分数据由于宕机而丢失,从而违背事务的持久性,InnoDB还会有一个Redo log机制来保证持久性。 那问题来了,既然是做为一个缓存,那大小确定有限制,总不能把全部的数据页都读到内存中来吧,因此缓存淘汰机制确定是会有的,最典型的不就是LRU算法(最近最久未使用)么?没错,InnoDB用的也是LRU,但不一样的是,它用的并非朴素的LRU算法:当有一个最新的页插入时,它并非插入到队列头,而是默认会插入到队列5/8的的位置,为啥要这么设计呢?其实是为了让真正的热门数据页不要为刷出去。 考虑这样的状况:内存中存有一堆热门数据页,此时来了一个不多执行的大范围查询,涉及不少数据页,若是使用朴素的LRU,那么原来真正的热门数据页就全被刷走了,从而对性能产生影响。线程

Redo log Buffer

Redo log的存在就是为了保证事务的持久性,它记录的内容并非像bin log那样的sql语句,它记录的其实是数据页的物理偏移量,一条修改操做的执行,实际上得先在redo log buffer中记录,而后再去到内存中的数据页进行更新,redo log buffer会在合适的时机刷新到磁盘中的redo log file里面,后续若是须要重启恢复数据,都是基于redo log file去作的,刷新的时机有几个:设计

  • 当事务提交时,会将redo log buffer的修改刷新到redo log file中
  • Master Thread会以每秒一次的频率进行数据刷新
  • 当redo log buffer大小占用达到阈值(默认是8M)的一半时,就进行一次刷新 那这样的话,又衍生了两个问题:文件大小脏页刷新到一半宕机,这两个分别使用checkpoint和**双写(double write)**来解决

Check Point

由于redo log file是以一种增量追加的方式写入,因此随着进程运行,file会一直膨胀,这涉及到一个空间问题;而且进行重作的时候,须要对整个file进行重作,这又是一个时间问题。然而事实上,重作日志里面记录的信息,有不少是已经落盘了,对于这些信息是不必进行重作的,因此就有了CheckPoint这个机制 Check Point能够理解为在重作日志中的一个指针,当一个脏页刷新回磁盘的时候,Check Point就向前移动,意义就是:Check Point以前的修改已经落盘了,重作的时候能够忽视,而且能够被覆盖;Check Point以后的数据还没落盘,恢复的时候须要重作,且不能被覆盖。 这样就解决了文件大小和恢复时间的问题指针

双写(double write)

因为redo log file记录的只是数据页的一个物理偏移量,因此若是原来的数据页发生了变换,那它是没法正常重作的。好比说,Mysql的一个数据页默认是16Kb大,在进行脏页刷新的时候,若是刷了前面的8Kb,而后宕机了,这样磁盘中的数据页已经被修改了,再根据重作日志进行恢复是没有意义的,因此必须有一个机制,在脏页彻底刷新以前,必须维护着一个原始的副本,这样即便脏页刷新到一半失败了,还能够将数据页恢复成副本,而后再进行重作日志

此时就是double write大显身手的时候了。double wirite机制相关的有两个部分:存在于内存上的double write buffer磁盘上的共享表空间

脏页在进行刷新以前,必须把对应的脏页复制到doule write buffer中

第一次写

把double write buffer中的脏页写到磁盘的共享表空间上,做为该数据页的一个备份

第二次写

把double write buffer中的脏页刷新到磁盘表数据文件中

若第二次写发生了错误,那直接从共享表空间上进行恢复,而后进行redo,就能够完成数据的备份

插入缓冲

前面提到了,对于一些修改操做好比插入,InnoDB会将插入操做先同步到内存中的数据页使之成为脏页,那问题来了,若是对应的数据页没有在内存中呢?要从磁盘中拿出来吗?那也太麻烦了。因此Insert Buffer就出现了,当对应的数据页没有在内存中的话,那这条插入记录会先记录在Insert Buffer中,等到合适的时机再会合并到数据页上,那这个时机主要有两个:

  • 对应的数据页从磁盘中被读到内存中了,此时刚好能够写入
  • Master Thread会以每10秒一次的几率进行一次插入缓冲的合并 固然了,插入缓冲也是在任什么时候候都会使用的,有一些限制:
  • 对应的数据存在辅助索引(也就是非主键索引)
  • 对应的索引不是惟一索引,由于惟一索引每次插入以前都得判断一下是否破坏了惟一性,这种数据是没办法缓冲的

那说了这么多,Insert Buffer究竟是个啥?其实它就是一个B+树的结构,在以前的版本中,每一个表都有这么一个Insert Buffer B+树,而在以后,变成了全局一个,按照表的全局惟一Id进行区分

自适应哈希索引

当以相同的模式(指的是相同的条件条件)对同一个页进行连续访问后,InnoDB会认为这些页是热门页,为这些页创建哈希索引,这种哈希索引就叫作自适应哈希索引。自适应哈希索引的创建有两个条件,知足其中一个便可:

  • 以相同的模式对该数据页查询了100次
  • 以相同的模式对该数据页查询了N次,N为该数据页数据行总数的1/16
相关文章
相关标签/搜索