1、buffer pool能在运行期间动态调整大小吗?

buffer pool在运行期间可以动态的调整自己的大小,但是这个过程极为耗时,性能很低下,不可以接受

动态调整buffer pool大小是怎么实现的呢? 比如buffer pool本来是8G,运行期间你给调整为16G了,需要向操作系统申请一块新的16GB的连续内存,然后把现在的buffer pool中的所有缓存页、描述数据块、各种链表,都拷贝到新的16GB的内存中去。

2、如何基于chunk机制把buffer pool拆小?

MySQL设计了一个chunk机制:buffer pool由很多chunk组成,它的大小是innodb_buffer_pool_chunk_size参数控制的,默认值128MB。

比如现在给buffer pool设置一个总大小8GB,有4个buffer pool,每个buffer pool2GB,此时每个buffer pool是由一系列的128MB的chunk组成的,也就是说每个buffer pool会有16个chunk。

每个buffer pool里的每个chunk里就是一系列的描述数据块和缓存页,每个buffer pool里的多个chunk共享一套free、flush、lru这些链表,大致如下图所示:
image.png
每个buffer pool里已经有了多个chunk,每个chunk就是一系列的描述数据块和缓存页,这样的话,就是把buffer pool按照chunk为单位,拆分为了一系列的小数据块,但是每个buffer pool共用一套free、flush、lru的链表。

3、基于chunk机制是如何支持运行期间,动态调整buffer pool大小的?

buffer pool现在总大小是8GB,要动态加到16GB,那么此时只要申请一系列的128MB大小的chunk分配给buffer pool。基于chunk机制,此时并不需要额外申请16GB的连续内存空间和把已有的数据进行拷贝。

4、生产环境中应该给buffer pool设置多少内存?

数据库部署在一台机器上,这台机器可能有个8G、16G、32G、64G、128G的内存大小,那么此时buffer pool应该设置多大呢?

操作系统内核要用掉起码几个GB的内存,机器上可能还有别的东西运行,数据库除了buffer pool还有别的内存数据结构,也要内存,所以如果胡乱设置一个特别大的内存给buffer,会导致mysql启动失败,启动的时候就发现操作系统的内存根本不够用。

所以通常来说,建议一个健康的比例,给buffer pool设置你的机器内存的50%~60%左右。比如你有32GB的机器,那么给buffer设置个20GB的内存,剩下的留给OS和其他,比较合理。

5、buffer pool总大小=(chunk大小 * buffer pool数量)的2倍数

确定了buffer pool的总大小之后,就得考虑一下设置多少个buffer pool,以及chunk的大小了。有一个很关键的公式就是:

  1. buffer pool总大小=(chunk大小 * buffer pool数量)的2倍数。

比如默认的chunk大小是128MB,那么此时如果你的机器的内存是32GB,你打算给buffer pool总大小在20GB左右,那么你得算一下,此时你的buffer pool的数量应该是多少个呢?

假设buffer pool的数量是16个,这是没问题的,那么此时chunk大小 buffer pool的数量 = 16 128MB = 2048MB,然后buffer pool总大小如果是20GB,此时buffer pool总大小就是2048MB的10倍,这就符合规则了。

当然,此时可以设置多一些buffer pool数量,比如设置32个buffer pool,那么此时buffer pool总大小(20GB)就是(chunk大小128MB * 32个buffer pool)的5倍,也是可以的。

6、SHOW ENGINE INNODB STATUS
当数据库启动之后,可以通过上述命令,去查看当前innodb里的一些具体情况,执行SHOW ENGINE INNODB STATUS

Total memory allocated xxxx;            buffer pool最终的总大小

Dictionary memory allocated xxx

Buffer pool size   xxxx                        buffer pool一共能容纳多少个缓存页

Free buffers       xxx                        free链表中一共有多少个空闲的缓存页是可用的

Database pages     xxx                        lru链表中一共有多少个缓存页,以及

Old database pages xxx                        冷数据区域里的缓存页数量

Modified db pages  xxx                        flush链表中的缓存页数量

Pending reads 0                                        等待从磁盘上加载进缓存页的数量

Pending writes: LRU 0, flush list 0, single page 0即将从lru链表中刷入磁盘的数量、即将从flush链表中刷入磁盘的数量

Pages made young xxxx, not young xxx        已经lru冷数据区域里访问之后转移到热数据区域的缓存页的数量,在lru冷数据区域里1s内被访问了没进入热数据区域的缓存页的数量

xx youngs/s, xx non-youngs/s                        每秒从冷数据区域进入热数据区域的缓存页的数量,以及每秒在冷数据区域里被访问了但是不能进入热数据区域的缓存页的数量

Pages read xxxx, created xxx, written xxx        已经读取、创建和写入了多少个缓存页,以及每秒钟读取、创建和写入的缓存页数量

xx reads/s, xx creates/s, 1xx writes/s

Buffer pool hit rate xxx / 1000,  每1000次访问,有多少次是直接命中了buffer pool里的缓存的

young-making rate xxx / 1000 not xx / 1000    每1000次访问,有多少次访问让缓存页从冷数据区域移动到了热数据区域,以及没移动的缓存页数量

Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s

LRU len: xxxx, unzip_LRU len: xxx        lru链表里的缓存页的数量

I/O sum[xxx]最近50s读取磁盘页的总数

I/O cur[xx]现在正在读取磁盘页的数量

I/O unzip sum[16xx:cur[0]