您的位置:首页 > 数据库 > MySQL

MySQL InnoDB存储引擎的内存及其管理

2015-10-14 16:55 691 查看

MySQL InnoDB存储引擎的内存及其管理

作为一个支持事物的的存储引擎,InnoDB存储引擎有着极其广泛的应用,因为事物的复杂性,也导致了关系型数据库的内存管理的复杂性,本文就是来研究一下InnoDB存储引擎的内存的使用,以及其管理的方式。InnoDB的内存可以分为三大块,buffer pool,redo log_buffer和额外内存池,它们的关系如下图所示:



从上图中我们可以看出,InnoDB的内存总共可以分为三块,分别为redo日志缓存池,额外缓存池和buffer pool,我们特别需要注意的就是redo日志缓冲不是在buffer pool中分配的,也就是说innodb_buffer_pool_size所指定的大小是不包含redo_log_buffer_size的,另外我们也需要格外注意一下额外缓冲池,这个是很容易被忽略的,应该在buffer pool很大的情况下关注一下额外缓冲池。下面我们就来讨论一下这三种缓冲池。

1)buffer pool

buffer pool对于InnoDB的性能是至关重要的,(关于缓存技术对于数据库性能的影响,我想大家都已经很清楚了,这里也就不再赘述)它的作用和Oracle的SGA是相同的,只是比起Oracle的SGA简单了很多。在buffer pool主要缓存的数据有数据页,索引页,插入缓存,自适应哈希索引,锁的信息以及数据字典的信息等等,这些信息对于MySQL的性能都是很重要的。它的大小是由参数innodb_buffer_pool_size决定的,关于这个参数的设置,很多DBA都已经将这个参数设置为了服务器内存的80%,不过这个值也要根据MySQL服务器的实际的压力来设置,也并不是设置的越大越好。我们先来看一下这个参数:

mysql> show variables like 'innodb_buffer_pool_size';

+----------------------------------+----------------+

| Variable_name | Value |

+----------------------------------+----------------+

| innodb_buffer_pool_size | 134217728 |

+----------------------------------+----------------+

1 row in set (0.00 sec)

这说明在我的系统上,buffer pool的大小为128M,那么InnoDB存储引擎是怎么管理着128M的内存的呢?要回答这个问题我们先要了解一下InnoDB中三个重要的列表,分别为LRU list,Free list和flush list。首先来看一下LRU列表。在InnoDB的缓冲中都是由page组成的(Oracle是叫做block,叫法不同,实质都是一样的),InnoDB对缓存的管理实际上就是对这些page的管理,InnoDB将数据以page为单位从磁盘读取到缓冲中,然后放在一个list上,这个list就是LRU
list,对于LRU list的管理InnoDB使用的是LRU算法,当一个新的page从磁盘读取到缓存中去,首先会去Free list上去申请一个page,当free list中也没有空闲的页时,则使用LRU算法从LRU list找出一个页给新的数据使用,然后将这个新的数据页放在LRU list的midpoint的位置。这样我们就很容易理解free list上面存放的实际上是缓存中空闲的可以使用的页,而midpoint的位置是由参数innodb_old_block_pct来定的,这个参数是1-100之间一个数,比如MySQL默认为75,指的是在LRU
List列表上,距离尾部75%的位置,如果经常使用的page经常被刷出缓存(缓存命中率很低),则可以调整这个参数。根据MySQL官方和google工程师的测试,这个参数设置为80是性能最佳的,这和MySQL默认的75是比较吻合的。另外,Flush List也是InnoDB存储引擎中一个很重要的列表,这个列表主要存放了还没有刷新到磁盘上的脏页,要注意一点,脏页是存在于LRU list和flush list上,这三个列表的关系如下图所示:



我们可以通过show engine innodb status \G;命令来观察一下我上面说的这些

mysql> show engine innodb status \G;

*************************** 1. row ***************************

Type: InnoDB

Name:

Status:

=====================================

2015-10-15 16:29:58 7f16a4059700 INNODB MONITOR OUTPUT

=====================================

Per second averages calculated from the last 59 seconds

-----------------

BACKGROUND THREAD

-----------------

...(此处有省略)

----------------------

BUFFER POOL AND MEMORY

----------------------

Total memory allocated 137363456; in additional pool allocated 0

Dictionary memory allocated 349555

Buffer pool size 8191

Free buffers 7713

Database pages 477

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 477, created 0, written 1

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: 477, unzip_LRU len: 0

I/O sum[0]:cur[0], unzip sum[0]:cur[0]

--------------

ROW OPERATIONS

...(此处有省略)

----------------------------

END OF INNODB MONITOR OUTPUT

============================

1 row in set (0.00 sec)

ERROR:

No query specified

通过上面的结果我们可以知道:

1)Buffer pool一共有8192个page,8192*16K/1024=128M,这和我们的参数innodb_buffer_pool_size是吻合的。

2)Free buffers为7713,说明现在系统中空闲的page为7713个page,这个Free buffers的数量会随着系统的运行而逐渐减少。

3)Database pages为477,说明现在系统缓存了477个页,我们查看下面的LRU len确实为477。如果想要知道这477个页具体是什么页的话,我们可以查看information_chema.innodb_buffer_pages_lru这张表,

mysql> select count(*) from information_schema.innodb_buffer_page_lru;

+----------+

| count(*) |

+----------+

| 477 |

+----------+

1 row in set (0.01 sec)

每一个page都会在这个表中有一条记录,也是这个lru list上页的具体信息,有需要的可以仔细研究一下。

4)Old database pages就是在lru list上的old(尾或者说cold)端的page数,此时为零,说明现在477个页都是位于new(头或者说hot)端的。

5)Modified db pages就是还没有刷新到磁盘上的脏页的数量,此时为零,说明磁盘上和缓存中的数据是一致的,若这个值一直处于很高的值,则说明此时系统压力较大,或者io较差。

6)Pending reads和Pending write不在本片文章的讨论范围类,此处先略过。

7)page make young是指当页从LRU列表的old部分加入到new部分时发生的操作,而因为innodb_old_blocks_time的设置而导致页没有从old部分移动到new部分的操作称为page not made young

8)unzip_lru,对于压缩表的压缩比率可能各不相同,可能存在有的表页的大小为8K,有的表页大小为2K的情况,unzip_lru就是缓存这些页的。需要注意的是unzip_lru是包含在lru len中的。unzip_lru列表对于不同压缩页的页分别进行管理,使用伙伴算法进行内存分配。例如对需要从缓冲池中申请一个4K的页,首先检查4K的unzip_lru列表,检查是否有可用的页,若有则直接使用,若没有则检查8K的unzip_lru列表,若能找到空闲页,则将其分裂为两个4K的页,存放到4K的unzip_lru列表上,若不能找到空闲页,则从lru列表中拿出一个16K的页,分裂成一个8K(存放在8K的unzip_lru列表上),两个4K(存放在4K的unzip_lru列表上)

另外关于buffer pool还有一个参数需要注意,就是innodb_buffer_pool_instances,这是说一个MySQL数据库可以设置多个buffer pool instance,以提高数据库的处理能力和并行能力。

2.redo log buffer

因为InnoDB redo日志的缓冲区,因为在介绍master thread的时候,我们知道每秒钟和每十秒都会刷新redo日志磁盘文件中,所以这个redo log buffer使用默认值就够了,它的大小由参数innodb_log_buffer_size决定,默认为8M。

3.额外缓冲池

很多人很容易忽略这个缓冲池,它简单理解就是缓冲buffer pool的元数据的,所以当buffer pool很大时,我们需要额外的关注一下这个缓冲池,它的大小由参数innodb_additional_mem_size决定,默认的是8M,对一般的系统可以了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: