[MySQL] Buffer Pool Adaptive Flush

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDSClaw,2核4GB
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
简介:

Buffer Pool Adaptive Flush

MySQL的帮助文档中Tuning InnoDB Buffer Pool Flushing提到, innodb_adaptive_flushing_lwm,innodb_max_dirty_pages_pct_lwm, innodb_io_capacity_maxinnodb_flushing_avg_loops. 公式决定了Adaptive Flush刷入的page数。

For systems with constant heavy workloads, or workloads that fluctuate widely, several configuration options let you fine-tune the flushing behavior for InnoDB tables: innodb_adaptive_flushing_lwm,innodb_max_dirty_pages_pct_lwm, innodb_io_capacity_max, and innodb_flushing_avg_loops. These options feed into the formula used by the innodb_adaptive_flushing option.

Innodb_adaptive_flush_lwm:自适应flush机制的低水位。
innodb_max_dirty_page_pct_lwm:脏页的低水位,用来控制buffer pool脏页比率。
innodb_io_capacity_maxredo log最大容量,如果不设置是innodb_io_capacity的两倍。
innodb_flushing_avg_loopsn次循环后,重新计算平均刷新的dirty pageLSN

要刷新多少pagelsn主要代码在af_get_pct_for_dirtyaf_get_pct_for_lsn

主要控制adaptive flush的代码位于buf0flu.ccaf_get_pct_for_lsn中:

1.先判断redo log的容量是否到了innodb_adaptive_flushing_lwm低水位阀值。
2.是否配置了adaptive flush或者age超过了异步刷新的阀值。
3.lsn_age_factor=age占异步刷新阀值的比例。
4.要被刷新的比率=innodb_io_capacity_max/innodb_io_capacity*lsn_age_factor* sqrt(innodb_io_capacity)/7.5

复制代码
static
ulint
af_get_pct_for_lsn(
/*===============*/
       lsn_t  age)   /*!< in: current age of LSN. */
{
       lsn_t  max_async_age;
       lsn_t  lsn_age_factor;
       lsn_t  af_lwm=(srv_adaptive_flushing_lwm
                       *log_get_capacity())/100;
 
       if(age<af_lwm){
              /* No adaptive flushing. */
              return(0);
       }
 
       max_async_age=log_get_max_modified_age_async();
 
       if(age<max_async_age&&!srv_adaptive_flushing){
              /* We have still not reached the max_async point and
              the user has disabled adaptive flushing. */
              return(0);
       }
 
       /* If we are here then we know that either:
       1) User has enabled adaptive flushing
       2) User may have disabled adaptive flushing but we have reached
       max_async_age. */
       lsn_age_factor=(age*100)/max_async_age;
 
       ut_ad(srv_max_io_capacity>=srv_io_capacity);
       return(static_cast<ulint>(
              ((srv_max_io_capacity/srv_io_capacity)
              *(lsn_age_factor*sqrt((double)lsn_age_factor)))
              /7.5));
}
复制代码

 

和要刷新多少脏页有关的函数是af_get_pct_for_dirty
1.如果有脏页,并且innodb_max_dirty_pages_pct=0立马刷新。
2.如果没有设置innodb_max_dirty_pages_pct_lwm,并且脏页比率超过innodb_max_dirty_pages_pct,立马刷新。
3.设置了innodb_max_dirty_pages_pct_lwm并且脏页比率比低水位大,af_get_pct_for_dirty =脏页比率/(innodb_max_dirty_pages_pct+1)

复制代码
static
ulint
af_get_pct_for_dirty()
/*==================*/
{
       ulintdirty_pct=buf_get_modified_ratio_pct();
 
       if(dirty_pct>0&&srv_max_buf_pool_modified_pct==0){
              return(100);
       }
 
       ut_a(srv_max_dirty_pages_pct_lwm
            <=srv_max_buf_pool_modified_pct);
 
       if(srv_max_dirty_pages_pct_lwm==0){
              /* The user has not set the option to preflush dirty
              pages as we approach the high water mark. */
              if(dirty_pct>srv_max_buf_pool_modified_pct){
                     /* We have crossed the high water mark of dirty
                     pages In this case we start flushing at 100% of
                     innodb_io_capacity. */
                     return(100);
              }
       }elseif(dirty_pct>srv_max_dirty_pages_pct_lwm){
              /* We should start flushing pages gradually. */
              return((dirty_pct*100)
                     /(srv_max_buf_pool_modified_pct+1));
       }
 
       return(0);
}
复制代码

 

要刷新的page=PCT_IO(max(af_get_pct_for_dirtyaf_get_pct_for_lsn))+avg_page(由innodb_flushing_avg_loops到期计算得到)。

要刷新到的LSN= oldest_lsn+(这次要刷新的page/上次已经刷新的page)+1*avg_lsn(innodb_flushing_avg_loops到期计算得到)

帮助文档还提到innodb_flushing_avg_loops越大,也意味着adaptive flush越慢,但是从代码看,innodb_flushing_avg_loops会影响所有的flush不单单是adaptive。当写入变大,innodb_flushing_avg_loops不变或者变大,是有可能导致flush跟不上。

复制代码
static
ulint
page_cleaner_flush_pages_if_needed(void)
/*====================================*/
{
       staticlsn_t         lsn_avg_rate=0;
       staticlsn_t         prev_lsn=0;
       staticlsn_t         last_lsn=0;
       staticulint         sum_pages=0;
       staticulint         last_pages=0;
       staticulint         prev_pages=0;
       staticulint         avg_page_rate=0;
       staticulint         n_iterations=0;
       ……
       cur_lsn=log_get_lsn();
 
       if(prev_lsn==0){
              /* First time around. */
              prev_lsn=cur_lsn;
              return(0);
       }
 
       if(prev_lsn==cur_lsn){
              return(0);
       }
 
       /* We update our variables every srv_flushing_avg_loops
       iterations to smooth out transition in workload. */
       if(++n_iterations>=srv_flushing_avg_loops){
 
              avg_page_rate=((sum_pages/srv_flushing_avg_loops)
                            +avg_page_rate)/2;
 
              /* How much LSN we have generated since last call. */
              lsn_rate=(cur_lsn-prev_lsn)/srv_flushing_avg_loops;
 
              lsn_avg_rate=(lsn_avg_rate+lsn_rate)/2;
 
              prev_lsn=cur_lsn;
 
              n_iterations=0;
 
              sum_pages=0;
       }
 
       oldest_lsn=buf_pool_get_oldest_modification();
 
       ut_ad(oldest_lsn<=log_get_lsn());
 
       age=cur_lsn>oldest_lsn?cur_lsn-oldest_lsn:0;
 
       pct_for_dirty=af_get_pct_for_dirty();
       pct_for_lsn=af_get_pct_for_lsn(age);
 
       pct_total=ut_max(pct_for_dirty,pct_for_lsn);
 
       /* Cap the maximum IO capacity that we are going to use by
       max_io_capacity. */
       n_pages=(PCT_IO(pct_total)+avg_page_rate)/2;
 
       if(n_pages>srv_max_io_capacity){
              n_pages=srv_max_io_capacity;
       }
 
       if(last_pages&&cur_lsn-last_lsn>lsn_avg_rate/2){
              age_factor=static_cast<int>(prev_pages/last_pages);
       }
       ……
       prev_pages=n_pages;
       n_pages=page_cleaner_do_flush_batch(
              n_pages,oldest_lsn+lsn_avg_rate*(age_factor+1));
 
       last_lsn=cur_lsn;
       last_pages=n_pages+1;
 
       ……
 
       if(n_pages){
              ……
              sum_pages+=n_pages;
       }
 
       return(n_pages);
}
复制代码

 

参考文档:

[1] http://dev.mysql.com/doc/refman/5.6/en/innodb-lru-background-flushing.html 14.12.1.6 Tuning InnoDB Buffer Pool Flushing
[2] http://hedengcheng.com/?p=88 InnoDB原生Checkpoint策略及各版本优化详解
[3] http://mysqllover.com/?p=620 Innodb:如何计算异步/同步刷脏及checkpoint的临界范围




    本文转自 Fanr_Zh 博客园博客,原文链接:http://www.cnblogs.com/Amaranthus/p/4450840.html,如需转载请自行联系原作者




相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
缓存 关系型数据库 MySQL
MySQL并发支撑底层Buffer Pool机制详解
【10月更文挑战第18天】在数据库系统中,磁盘IO操作是性能瓶颈之一。为了提高数据访问速度,减少磁盘IO,MySQL引入了缓存机制。其中,Buffer Pool是InnoDB存储引擎中用于缓存磁盘上的数据页和索引页的内存区域。通过缓存频繁访问的数据和索引,Buffer Pool能够显著提高数据库的读写性能。
681 2
|
存储 SQL 关系型数据库
mysql的undo log、redo log、bin log、buffer pool
MySQL的undo log、redo log、bin log和buffer pool是确保数据库高效、安全和可靠运行的关键组件。理解这些组件的工作原理和作用,对于优化数据库性能和保障数据安全具有重要意义。通过适当的配置和优化,可以显著提升MySQL的运行效率和数据可靠性。
334 16
|
存储 SQL 关系型数据库
mysql的undo log、redo log、bin log、buffer pool
MySQL的undo log、redo log、bin log和buffer pool是确保数据库高效、安全和可靠运行的关键组件。理解这些组件的工作原理和作用,对于优化数据库性能和保障数据安全具有重要意义。通过适当的配置和优化,可以显著提升MySQL的运行效率和数据可靠性。
241 4
|
缓存 关系型数据库 MySQL
图解MySQL【日志】——Buffer Pool
Buffer Pool 是数据库管理系统(DBMS)中用于缓存磁盘数据页的内存区域,主要包含数据页、索引页、undo 页等。它通过减少磁盘 I/O 提升性能,特别是在处理大型数据库时效果显著。查询时,整个数据页而非单条记录会被加载到 Buffer Pool 中,以提高访问效率。
367 0
图解MySQL【日志】——Buffer Pool
|
存储 缓存 关系型数据库
MySQL进阶突击系列(08)年少不知BufferPool核心原理 | 大哥送来三条大金链子LRU、Flush、Free
本文深入探讨了MySQL中InnoDB存储引擎的buffer pool机制,包括其内存管理、数据页加载与淘汰策略。Buffer pool作为高并发读写的缓存池,默认大小为128MB,通过free链表、flush链表和LRU链表管理数据页的存取与淘汰。其中,改进型LRU链表采用冷热分离设计,确保预读机制不会影响缓存公平性。文章还介绍了缓存数据页的刷盘机制及参数配置,帮助读者理解buffer pool的运行原理,优化MySQL性能。
|
存储 缓存 关系型数据库
深度解密 MySQL 的 Buffer Pool
深度解密 MySQL 的 Buffer Pool
378 1
|
SQL 缓存 关系型数据库
(十二)MySQL之内存篇:深入探寻数据库内存与Buffer Pool的奥妙!
MySQL是基于磁盘工作的,这句几乎刻在了每个后端程序员DNA里,但它真的对吗?其实答案并不能盖棺定论,你可以说MySQL是基于磁盘实现的,这点我十分认同,但要说MySQL是基于磁盘工作,这点我则抱否定的态度,至于为什么呢?这跟咱们本章的主角:Buffer Pool有关,Buffer Pool是什么?还记得咱们在《MySQL架构篇》中聊到的缓存和缓冲区么,其中所提到的写入缓冲区就位于Buffer Pool中。
1594 1
|
7月前
|
缓存 关系型数据库 BI
使用MYSQL Report分析数据库性能(下)
使用MYSQL Report分析数据库性能
505 158
|
7月前
|
关系型数据库 MySQL 数据库
自建数据库如何迁移至RDS MySQL实例
数据库迁移是一项复杂且耗时的工程,需考虑数据安全、完整性及业务中断影响。使用阿里云数据传输服务DTS,可快速、平滑完成迁移任务,将应用停机时间降至分钟级。您还可通过全量备份自建数据库并恢复至RDS MySQL实例,实现间接迁移上云。
|
7月前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS费用价格:MySQL、SQL Server、PostgreSQL和MariaDB引擎收费标准
阿里云RDS数据库支持MySQL、SQL Server、PostgreSQL、MariaDB,多种引擎优惠上线!MySQL倚天版88元/年,SQL Server 2核4G仅299元/年,PostgreSQL 227元/年起。高可用、可弹性伸缩,安全稳定。详情见官网活动页。
1272 152

推荐镜像

更多