#### InnoDB龙骨
就目前InnoDB存储引擎的结构来看是由多个后台线程+一个内存缓冲区对数据文件进行的读写,一共有4中线程分别是Master Thread ,I/O Thread,Purge Thread ,Page Cleaner Thread,接下来我们则分别来介绍这4个线程的主要处理的事情。
后台线程
-
Master Thread
主控制线程,负责从内存数据缓冲池把数据写入文件,脏页处理,合并插入缓冲,undo页的回收
-
I/O Thread
用于处理数据库读写数据AIO的回调,io线程主要有4个小分类,分别是读,写 日志,患有插入缓存。在linux上由于aio的支持不是很好,所以无法使用参数调整io线程额数目,但是在win上面是可以的,InnoDB 1.0版本之前是可以在my.ini文件中使用
innodb_file_io_threads
来增大线程的个数,之后的版本呢则是废弃了该参数,使用更加独立的参数来设置读和写的io线程的个数。分别是innodb_read_io_threads
和innodb_write_io_threads
。我们可以在client命令行执行show ENGING INNODB STATUS查看io线程的状态。0号线程是插入缓存线程,1号是日志线程,然后是读取线程,写入线程,读取线程的id一般是比写入线程的要小。 -
Purge Thread
用来回收事务提交的之后的undo页,在1.1版本之后从master独立出来,减轻master的压力,充分压榨硬件CPU的能力,在刚独立出来的时候只允许单线程的回收undo页,在1.2时候就支持多个线程了,使用磁盘的随机读取,高效的回收undo页。
-
Page Cleaner Thread
也是从Master中独立出来,用于清楚脏页的。
##### 内存缓冲区
说白了数据库就是一个基于磁盘文件系统,但是呢由于CPU的读写和磁盘的读取之间的速率鸿沟,所以innodb设计者增加一个内存数据缓池来提升数据库的访问性能,和缓存的原理是一样的,只不过池化之后更加优化,读取时候先把数据从磁盘读入池中,再有访问同一块数据的时候直接访问缓存池即可,节省了和磁盘交互,对于修改常理来说都是先写入缓存中,之后再刷入磁盘,innodb呢他的刷磁盘不是一有修改就去刷磁盘,而是有一个检查点的优化来处理。基于这种情况来理论上说,只要我们的缓存池够大,那我们的性能就是杠杠的,我们可以在my.ini文件中使用innodb_buffer_pool_size
来设置该缓存池的大小。在innodb 1.0版本之后允许多个缓冲池实例每一页根据hash值平均分配到不同的实例中减少额内部资源的竞争,增加了数据库的并发,使用innodb_buffer_pool_instances
来设置实例的个数。
缓存区的数据管理LRU算法
innodb的lru使用方式为,最频繁使用的页存放于双向链表的头部,不经常使用的放到双向链表的尾部,主要流程是当缓存区中无法存放新页的时候采取释放尾部的页,而新加入的页会存放在midpoint位置,一般是lru链表的5/8的位置,midpoint的位置之前的数据称为活跃数据,之后的称为相对不经常使用的。midpoint的位置可以由my.ini文件中使用innodb_old_blocks_pct
来设置。使用midpoint是因为如果直接把新页放入头部,可能导致原来的活跃数据被刷入磁盘,这样的话会增加访问磁盘的次数,从而影响了缓存的效率,但是只要是新数据就加入midpoint的话,显然不满足lru的策略,所以innodb增加一个阈值来控制midpoint的数据进行移动。在sql执行之前 执行set global innodb_old_blocks_time=111
来控制页读取到midpoint之后等待111只后进行位置移动,移动到头部。具体的缓存置换策略要设计三个列表 lru free flush
数据库实例启动的时候lru链表为空,这是所有的页都放在free中