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/ ,如需转载,请注明出处,否则将追究法律责任。