InnoDB Plugin特性介绍:让Buffer Pool不被污染

较之MyISAM的一个很大的优势是,InnoDB会缓存数据块。如果系统中的数据量并不大,或者或者活跃数据量并不大时,InnoDB会将这些数据块全部缓存到Buffer Pool(内存)中,这样可以最大限度的提高提供的响应速度,特别是读取。当用户请求需要查询数据块时,InnoDB会首先在Buffer Pool中查找数据,如果Buffer Pool中没有该数据块时,InnoDB会从磁盘上Load对应的数据块,并通过LRU算法替代当前Buffer Pool的缓存块。

1. Buffer Pool中LRU缺点、细节

这样LRU算法的一个缺点是,如果有某一个查询做了一次全表扫描(例如备份,临时DDL等),都可能会导致整个Buffer Pool中LRU链表中的数据块都被替换了,甚至很多热点数据也会被替换,而这些新进的数据块可能在这一次查询之后就再也不会被读到了。我们也称这种情况为“Buffer Pool被污染”了。

在InnoDB则引入了一些新的机制来避免这种情况。算法仍然是LRU算法,但是加上了中点策略(类似于MyISAM的key buffer中的midpoint strategy)。同时引入了参数innodb_old_blocks_time来控制Buffer Pool不被污染。

LRU链表中的数据分为两部分:Sublist of new和Sublist of old。后者包含访问最近没有访问的数据块(链表越后面的数据块,最近越没有被访问)。默认情况,前者占63%(5/8),后者37%(3/8)。

BufferPoolLRU

当数据块需要从数据文件中读取时,首先会放到old sublist的头部(midpoint)。然后,如果有对这个数据块的访问,那么就将这个数据块放到new sublist的首部。一般来说,一个数据块被取出后,立刻会有读取,也就很快会被放到new sublist的头部。一种糟糕的情况是,如果是mysqldump访问全部数据块,也就会导致所有的数据块被放到new sublist。这样Buffer Pool也就全部被污染了。

2. Buffer Pool中LRU队列如何防止污染

InnoDB Plugin通过引入如下的参数来防止“污染”:

innodb_old_blocks_pct: 控制old sublist在LRU队列的长度

innodb_old_blocks_time:该参数决定了,当Block被插入到midpoint(old sublist)后,必须要在old sublist停留超过innodb_old_blocks_time(ms)时间后,才有可能被转移到new sublist。例如,将innodb_old_blocks_time设置为1000(即1s),当出现Table scan出现时,InnoDB先将数据块载入到midpoint(old sublist)上,程序读取数据块,因为这时,数据块在old sublist中的停留时间还不到innodb_old_blocks_time,所以不会被转移到new sublist中。这就避免了Buffer Pool被污染的情况。更酷的是,这个参数是动态调整的,所以在做意外的Table scan时,动态调整一下该参数就可以了。

3. 防污染的效率观察

可以根据SHOW INNODB STATUS\G中Buffer Pool段开看看相关效率:

Total memory allocated 1107296256; in additional pool allocated 0
Dictionary memory allocated 80360
Buffer pool size 65535
Free buffers 0
Database pages 63920
Old database pages 23600
Modified db pages 34969
Pending reads 32
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 414946, not young 2930673
1274.75 youngs/s, 16521.90 non-youngs/s
Pages read 486005, created 3178, written 160585
2132.37 reads/s, 3.40 creates/s, 323.74 writes/s
Buffer pool hit rate 950 / 1000, young-making rate 30 / 1000 not 392 / 1000
Pages read ahead 1510.10/s, evicted without access 0.00/s
LRU len: 63920, unzip_LRU len: 0
I/O sum[43690]:cur[221], unzip sum[0]:cur[0]

解释:Old database pages 表示LRU列表中old sublist中的数据块数量。

Pages made young and not young表示old sublist中有多少数据块是(没)被转移到new sublist。

youngs/s and non-young/s 从上次执行SHOW INNODB STATUS到现在为止,访问Old sublist时有多少将数据块转移到new sublist,有多少是没有转移的(这里可以看出参数innodb_old_blocks_time的效率)。

young-making rate and not 反映的是全部Buffer Pool访问中,将(没有将)old sublist中转移new sublist的比率。

参考:

【1】. Making Buffer Cache Scan Resistant

In:

6 responses to “InnoDB Plugin特性介绍:让Buffer Pool不被污染”

  1. 有点接近于Oracle的buffer Cache策略了,,还可以考虑再添加一个Touch Count策略..:-)

  2. 图很赞,一看明了

    “当数据块需要从数据文件中读取时,首先会放到old sublist的头部(midpoint)。然后,如果有对这个数据块的访问,那么就将这个数据块放到new sublist的首部。”

    代码里面好像不是这样的喔 从old到new的条件不是取决于有没有被再次访问 而是根据old和new的数量调整的时候更新的

    不知道是否版本差异,我看的是5.1.48

  3. […] 原文链接 较之MyISAM的一个很大的优势是,InnoDB会缓存数据块。如果系统中的数据量并不大,或者或者活跃数据量并不大时,InnoDB会将这些数据块全部缓存到Buffer Pool(内存)中,这样可以最大限度的提高提供的响应速度,特别是读取。当用户请求需要查询数据块时,InnoDB会首先在Buffer Pool中查找数据,如果Buffer Pool中没有该数据块时,InnoDB会从磁盘上Load对应的数据块,并通过LRU算法替代当前Buffer Pool的缓存块。 […]

  4. […] InnoDB Plugin特性介绍:让Buffer Pool不被污染 – 一个故事@MySQL DBA. […]

  5. […] 这里 。和 innodb_old_blocks_pct […]

Leave a Reply

Your email address will not be published. Required fields are marked *