ITPub博客

首页 > 数据库 > MySQL > innodb buffer pool的3种list以及5.6 flushing的改进

innodb buffer pool的3种list以及5.6 flushing的改进

原创 MySQL 作者:myownstars 时间:2013-12-24 16:39:56 0 删除 编辑
Buffer pool采用3个链表维护内存页,而内存页也因此对应3种状态:free尚未使用;clean已使用但未修改;dirty已修改;

Free页只位于free list,而clean和dirty页同时位于LRU list,dirty页只存在于flush list;


Free list

其中的页尚未被使用,当页面被读入buffer时,首先尝试从free list分配空闲页,如不足则刷新LRU list;

在MySQL 5.6.2之前,用户线程在读入一个page (buf_read_page)、新建一个page(buf_page_create)、预读page(buf_read_ahead_linear) 等等操作时,都会在操作成功之后,调用buf_flush_free_margin函数,判断当前buffer pool是否有足够的free pages,若free pages不足,则进行LRU list flush,释放出足够的free pages,保证系统的可用性。

5.6.2则引入后台线程page_cleaner,通过buf_flush_page_cleaner_thread完成;


LRU list

每个buffer pool均各自维护了1条LRU list,结构如下

  new                  mid_point             old 

H1------------------------------|h2-------------------

Innodb提供很多参数可进行各种定制,如mid_point位置,何时从old移入new等.

Mid_point默认值为37,即old:new比例为3:5,可选范围为5-95,由 innodb_old_blocks_pct设置;

数据页从磁盘加载进buffer可分为两个阶段:1  加载进old list,放入h2;  2 被线程读取,转移到h1;

read-ahead后台线程预读的数据页,可能永远不会被线程访问则一直位于old list直至被清除,Innodb_buffer_pool_read_ahead_evicted记录此页数;

若一次性读取访问大量数据,则可能将new list中的常用数据页挤占至old list,甚至移出buffer.

参数innodb_old_blocks_time可缓解此状况,指定数据页在被访问N(ms)后才能放入new list,默认为0;

有个例外,当插入old list的数据页有1/4被移出 buffer时,新读取的页会被移入new list,不受此参数控制;

通过Show engine innodb status可以获取如下指标

Old database pages: 位于old list中的页数

Pages made young, not young: 从old list移到new list的页数,以及一直驻留在old list中的页数

Youngs/s non-youngs/s: 访问old list的页并导致其移入new list,则youngs/s增1,若该页仍驻留于old list,则non-youngs/s增1;记录的是针对old list页的访问次数;

Young-making rate:页被命中并移到new list

Not:页被命中但并未移到new list

后两个参数并不会增加buffer pool的整体命中率,对于已经位于new list的页 ,只有当它们距new list head超过一定距离时才会因再次命中而重返h1;

优化建议

1

若youngs/s值很低且没有大的表扫描,则可调低innodb_old_blocks_time参数或者增加old list的比重,这样可延长old list页在buffer的驻留时间,从而避免再次访问时产生磁盘读

2

若做大表扫描时youngs/s值很高(non-youngs/s很低),则可相应调高innodb_old_blocks_time参数, 避免new list页被过早移入old list


 

Flush list

按照时间顺序存放脏页(最旧的放队尾),当达到innodb_max_dirty_pages_pct阈值或执行检查点时刷新;

0-------------------------------.-----------------------------.--------------------.----------------log_size
                        checkpoint_age                async              sync
Checkpoint age
指的是buffer pool的最老脏页(=checkpoint_lsn – current_lsn),其不能漫过log size;

Innodb定义了两个临界点async和sync,当checkpoint_age到达此临界值时数据库会有相应动作;

async_water_mark:只阻塞当前线程,尽可能的刷新脏页,会严重消耗IO资源,pre-5.6调用buf_LRU_sacn_and_free_block完成

sync_water_mark:刷新脏页同时阻塞所有线程,直至checkpoint_age降回async,

0-------------------------------.----------------.------------.--------------------.----------------log_size
                        checkpoint_age    T            async              sync

为了尽可能的扩展checkpoint_age同时避免触及async/sync,一般建议增大innodb_io_capacity/减小innodb_max_dirty_pages_pct,但这可能会降低系统整体性能,为此Vadim引入T点;

确保checkpoint age位于T点左侧,可通过调整每秒刷新的脏页数实现,当其越过T点向async靠近时,则延阻DML操作减少redo的生成;

经Vadim测试,该机制很好的将IOPS维护在一个很稳定的状态

源码链接https://code.launchpad.net/~vadim-tk/+junk/crazy-flushing

注:5.6的page_cleaner很好的解决了此问题,Vadim应该是针对pre-5.6颁布开发的补丁。



 

区分LRU list和flush list的刷新

系统变量Innodb_buffer_pool_pages_flushed既包含LRU list,也包括flush list;

可通过show engine innodb status输出区分

Pending writes: LRU 0, flush list 129, single page

LRU list bound只能通过升级硬件完成,如增加内存和IO带宽

Flush list bound则可通过调整innodb_adaptive_flushing/innodb_max_dirty_pages_pct/innodb_io_capacity/innodb_log_file_size参数优化,5.6的page_cleaner某种程度上也可解决该问题


 

综上所述,仅从数据库角度,调优flush list刷新更切合实际一些。

为此innodb先后引入adaptive flushing和page cleaner后台线程

adaptive_flushing

类似oracle的增量检查点,在后台以一定的频率刷新脏,plugin 1.0.4引入此功能;

触发flushing两大诱因

1 没有足够free buffer,从LRU list选出页重用(如果脏页则先刷新),LRU_list flush

2 重用redo log导致刷新脏页 ,flush_list flush

如何计算每秒需要刷新的脏页?

日志切换频率N = log_capacity/redo_gen_rate redo

每秒需刷新的脏页数Required_flush_rate = n_dirtypages/N

不过上述公式没有把LRU_list flush计算入内

Desired_flush_rate = (n_dirtypages * redo_gen_rate)/log_capacity – LRU_flush_rate

保留LRU_flush_rate和redo_gen_rate的历史记录作为权重以使计算更精确

innodb_adaptive_flushing参数,用于开启或关闭此功能;

5.5.4引入多个buffer pool,每个都有LRU list


Page_cleaner

每秒唤醒1次,专门负责刷新LRU list & Flush list,而系统idle或shutdown引发的刷新也交由此线程处理(将master thread解脱出来);

前台线程只有在checkpoint_age > sync_water_mark时才会被阻塞,此时调用buf_flush_single_page_from_LRU一次从LRU list回收1个页

http://www.mysqlperformanceblog.com/2011/01/13/different-flavors-of-innodb-flushing/

http://www.mysqlperformanceblog.com/2011/04/04/innodb-flushing-theory-and-solutions/

http://www.mysqlperformanceblog.com/2011/03/31/innodb-flushing-a-lot-of-memory-and-slow-disk/

https://blogs.oracle.com/mysqlinnodb/entry/mysql_5_5_innodb_adaptive

https://blogs.oracle.com/mysqlinnodb/entry/introducing_page_cleaner_thread_in


 

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/15480802/viewspace-1064153/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2010-03-18

  • 博文量
    375
  • 访问量
    3320724