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,对一般的系统可以了。相关文章推荐
- MYSQL未启用存储引擎的启用办法
- mysql自动补全
- 转-MySQL for Mac 安装和基本操作
- mysql体系结构
- 转-解决Mysql ERROR 1045 (28000): Access denied for user 'root'@'localhost'问题
- MySQL按照汉字的拼音排序
- mysql cmake参数详解
- MySQL数据迁移问题
- MYSQL 添加序列号取数
- MySQL Study之--Mysql无法启动“mysql.host”
- 【MySQL】存储引擎总结(正确的使用存储引擎)
- mysql 忘记root密码
- MySQL杂记(不定期更新)
- mysql 快速生成百万条测试数据
- mysql 快速生成百万条测试数据
- Mac中MySQL无法显示中文全解决
- MySQL Study之--MySQL 备份
- Mysql 一主多实例与主从同步详解
- mysql创建新的用户及flush privileges解析
- mysql命令行自动补全工具 mycli