innodb体系结构
InnoDB有多个内存块,你可以认为这些内存块组成了一个大的内存池,负责如下的工作:
- 维护所有的进程/线程需要访问的多个内部数据结构
- 缓存磁盘上的数据,方便快速地读取,并且在对磁盘文件的数据进行修改之前在这里缓存
- 重做日志缓冲
后台线程的主要作用是负责刷新内存池中的数据,保证缓冲池中的内存缓存的是最近的数据。此外,将已修改的数据文件刷新到磁盘文件,同时保证在数据库发生异常情况下InnoDB能恢复到正常运行状态。
默认情况下,InnoDB存储引擎的后台线程有7个——4个IO thread, 1个master thread, 1个锁(lock)监控线程,1个错误监控线程。IO thread的数量由配置文件中的innodb_file_io_threads参数控制,默认为4.
mysql> show engine innodb status \G;
4个IO线程分别是insert buffer thread、log thread、read thread、write thread。在Linux平台下,IO thread数量不能进行调整,但是在Windows平台下可以通过参数 innodb_file_io_threads来增大IO thread。InnoDB Plugin版本开始增加了默认IO thread的数量,默认的read thread和write thread 分别增加到了4个,并且不再使用innodb_file_io_threads参数,二十分别使用innodb_read_io_threads和innodb_writer_io_threads参数。
mysql> show variables like 'innodb_version'; +----------------+--------+ | Variable_name | Value | +----------------+--------+ | innodb_version | 5.7.17 | +----------------+--------+ 1 row in set, 1 warning (0.00 sec)
mysql> show variables like 'innodb_%io_threads'; +-------------------------+-------+ | Variable_name | Value | +-------------------------+-------+ | innodb_read_io_threads | 4 | | innodb_write_io_threads | 4 | +-------------------------+-------+ 2 rows in set, 1 warning (0.00 sec)
内存
InnoDB存储内存由一下几个部分组成:缓冲池(buffer pool)、重做日志缓冲池(redo log buffer)以及额外的内存池(additional memery pool),分别由配置文件中的参数innodb_buffer_pool_size、innodb_log_buffer_size、innodb_additional_mem_pool_size的大小决定。
缓冲池是占最大块内存的部分,用来存放各种数据的缓存。因为InnoDB的存储引擎的工作方式总是将数据库文件按页(每页16K)读取到缓冲池,然后按LRU算法来保留在缓冲池中的缓存数据。如果数据库文件需要修改,总是首先修改在缓存池中的页(发生修改后,该页即为脏页),然后再按照一定的频率将缓冲池的脏页刷新(flush)到文件。可以通过命令SHOW ENGINE INNODB STATUS来查看innodb_buffer_pool的具体使用情况
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 137297920
Dictionary memory allocated 284078
Buffer pool size 8192
Free buffers 7721
Database pages 469
Old database pages 0
Modified db pages 0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 0, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 434, created 35, written 46
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 469, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
...
在BUFFER POOL AND MEMORY里可以看到InnoDB在存储引擎缓冲池的使用情况,buffer pool size 表明了一共有多少个缓冲帧(buffer frame),每个buffer frame为16K,所以这里一共分配了8192*16k=128M内存的缓冲池。Free buffers标识当前空闲的缓冲帧,Database pages表示已经使用的缓冲帧,Modified db pages标识脏页的数量。当前状态看来,这台数据库的压力并不大,因为在缓冲池中有大量的空闲页可供数据库进一步使用。
日志缓冲(严格讲是重做redo日志缓冲)将重做日志信息先放入这个缓冲区,然后按一定频率将其刷新到重做日志文件。该值一般不需要设置为很大,因为一般情况下每一秒钟就会将重做日志缓冲刷新到日志文件,因此我们只需要保证每秒产生的事务量在这个缓冲大小之内即可。 额外的内存池通常被DBA忽略,认为该值并不是十分重要,但恰恰相反的是,该值其实同样十分重要。在InnoDB存储引擎中,对内存的管理是通过一种称为内存堆(heap)的方式进行的。对一些数据结构本身分配内存时,需要从额外的内存池中申请,当该区域的内存不够时,会从缓冲池中申请。InnoDB实例会申请缓冲池(innodb_buffer_pool)的空间,但是每缓冲池中的缓冲帧(frame buffer)还有对应的缓冲控制对象(buffer control block),而且这些对象记录了诸如LRU、锁、等待等方面的信息,而这个对象的内存需要从额外内存池中申请。因为,当你申请了很大的InnoDB缓冲池时,这个值也应该相应增加。