mysql数据库 checkpoint_MySQL数据库InnoDB存储引擎原生Checkpoint策略及各版本优化详解...

Checkpoint原理

关于MySQL数据库InnoDB存储引擎 Checkpoint的原理,此处不准备介绍,推荐 How InnoDB performs a checkpoint

[2]一文,作者详细讲解了Innodb存储引擎的Checkpoint原理。

Checkpoint触发条件

每1S

若buffer pool中的脏页比率超过了srv_max_buf_pool_modified_pct =

75,则进行Checkpoint,刷脏页,flush PCT_IO(100)的dirty pages = 200

若采用adaptive flushing,则计算flush rate,进行必要的flush

每10S

若buffer pool中的脏页比率超过了70%,flush PCT_IO(100)的dirty pages

若buffer pool中的脏页比率未超过70%,flush PCT_IO(10)的dirty pages = 20

每10S,必定调用一次log_checkpoint,做一次Checkpoint

InnoDB存储引擎如何计算脏页比率?adaptive flushing时如何计算flush

rate?如何进行真正的flush操作,是否使用AIO,将在以下章节中一一分析。

Checkpoint流程

计算脏页比率

srv0srv.c::srv_master_thread -> buf0buf.c::buf_get_modified_ratio_pct -> buf_get_total_list_len

for (i = 0; i < srv_buf_pool_instances; i++) {

buf_pool_t* buf_pool;

buf_pool = buf_pool_from_array(i);

*LRU_len += UT_LIST_GET_LEN(buf_pool->LRU);

*free_len += UT_LIST_GET_LEN(buf_pool->free);

*flush_list_len += UT_LIST_GET_LEN(buf_pool->flush_list);

}

ratio = (100 * flush_list_len) / (1 + lru_len + free_len);

脏页比率 = 需要被flush的页面数 / (使用中的页面数 + 空闲页面数 + 1)

其中,所有的值,在buf_pool_t结构中均有统计,无需实际遍历buffer pool进行计算

计算adaptive flush rate

函数流程:

buf0buf.c::buf_flush_get_desired_flush_rate ->

从buf_pool_t结构中,获得总dirty page的数量

计算最近一段时间之内,redo日志产生的平均速度

redo_avg = (ulint) (buf_flush_stat_sum.redo/ BUF_FLUSH_STAT_N_INTERVAL+ (lsn – buf_flush_stat_cur.redo));

其中,BUF_FLUSH_STAT_N_INTERVAL = 20S,20S内的平均redo产生速度

#define

BUF_FLUSH_STAT_N_INTERVAL 20

flush的统计信息,每隔20S会被buf_flush_stat_update函数重置

计算过去一段时间内,flush的平均速度;与当前需要的flush速度

lru_flush_avg = buf_flush_stat_sum.n_flushed

/ BUF_FLUSH_STAT_N_INTERVAL

+ (buf_lru_flush_page_count

– buf_flush_stat_cur.n_flushed);

n_flush_req = (n_dirty * redo_avg) / log_capacity;

其中,BUF_FLUSH_STAT_N_INTERVAL = 20S不变,计算的仍旧是过去20S内的平均flush速度

若当前所需flush的page数量 > 20S flush的平均数量,则adaptive

flushing会尝试进行一次flush操作。flush的dirty pages数量最大是PCT_IO(100),200个dirty

pages。

flush dirty pages算法

函数流程:

buf0flu.c::buf_flush_list -> buf_flush_start ->

buf_flush_batch -> buf_flush_end -> buf_flush_common

首先,判断当前是否有正在进行的相同类型的flush (buf_flush_start),有则直接退出

buf_flush_batch ->

buf_flush_flush_list_batch -> buf_flush_page_and_try_neighbors

-> buf_flush_try_neighbors -> buf_flush_page ->

buf_flush_buffered_writes ->

从flush_list的最后一个页面开始,向前遍历页面 & flush

对于a)中的page,尝试flush,并且尝试flush该page的neighbors pages

(buf_flush_try_neighbors)

首先计算可选的neighbors范围。所谓neighbors范围,指的是space_id相同,page_no不同的page,只有这些page才是连续的。

buf_flush_area = ut_min(

ut_min(64, ut_2_power_up((b)->curr_size / 32)),

buf_pool->curr_size / 16);

low = (offset / buf_flush_area) * buf_flush_area;

high = (offset / buf_flush_area + 1) * buf_flush_area;

low为当前page,neighbors的范围既为buf_flush_area,最大64

neighbors为当前page开始,page_no连续递增的buf_flush_area个pages

所有的dirty pages,在buffer pool中同时以hash表存储,根据(space_id,

[page_no_low, page_no_high])到hash表中进行查找,若存在,则flush此dirty page

buf_flush_page -> buf_flush_write_block_low ->

log_write_up_to ->

flush脏页之前,必须保证脏页对应的日志已经写回日志文件(log_write_up_to)

判断是否需要使用double write

若不需要double write保护,直接调用fil_io进行flush操作,设置type =

OS_FILE_WRITE;mode = OS_AIO_SIMULATED_WAKE_LATER

若需要double write保护,则调用buf_flush_post_to_doublewrite_buf函数

写到double write就算完成,退出buf_flush_page

buf_flush_batch -> buf_flush_buffered_writes

buf_flush_batch函数,在完成2,3步骤,batch

flush之后,调用buf_flush_buffered_writes函数进行真正的write操作

buf_flush_buffered_writes:将double write memory写出到disk

我的测试中,有7个dirty pages,每个page大小为16k = 16384,因此doublewrite

buffer的大小为 16384 * 7 = 114688

doublewrite buffer的写,为同步写,调用fil_io(OS_FILE_WRITE, TRUE)

同步写之后,调用fil_flush函数,将doublewrite buffer中的内容flush到disk

windows:

FlushFileBuffers(file);

linux:

os_file_fsync(file); or

fcntl(file, F_FULLFSYNC, NULL);

在doublewrite buffer被成功flush到disk之后,对应的dirty

pages不会再丢失数据。此时再将doublewrite buffer对应的dirty pages写出到disk

fil_io(OS_FILE_WRITE | OS_AIO_SIMULATED_WAKE_LATER,

FALSE);

写dirty pages,采用非同步写 AIO

在dirty

pages都完成异步IO之后,调用buf_flush_sync_datafiles函数,将所有的异步IO操作,flush到磁盘

os_aio_simulated_wake_handler_threads();

os_aio_wait_until_no_pending_writes();

fil_flush_file_spaces(FIL_TABLESPACE);

标识当前flush操作结束(buf_flush_end)

收集当前flush操作的统计信息(buf_flush_common)

Checkpoint info更新

在完成Checkpoint流程中的flush dirty pages之后,Innodb

Checkpoint的大部分流程已经完成,只余下最后的修改Checkpoint Info信息。

流程一

更新Checkpoint Info流程一,流程一每10S调用一次:

srv_master_thread -> log0log.c::log_checkpoint ->

log_buf_pool_get_oldest_modification ->

读取系统中,最老的日志序列号。实现简单,读取lsn flush list中最老日志对应的lsn即可

log_write_up_to(oldest_lsn, LOG_WAIT_ALL_GROUPS, TRUE) ->

将日志flush到oldest_lsn

log_groups_write_checkpoint_info -> log_group_checkpoint

->

fil_io(OS_FILE_WRITE | OS_FILE_LOG, FALSE) ->

遍历所有日志组,分别更新每个日志组对应的Checkpoint Info

构造Checkpoint Info,使用os_aio_log_array进行异步写I/O操作

流程二

更新Checkpoint Info流程二,在I/O较为繁忙的系统中,流程二每1S调用一次:

srv_master_thread -> log0log.ic::log_free_check -> log0log.c::log_check_margins ->

log_checkpoint_margin -> log_preflush_pool_modified_pages -> log_checkpoint

读取当前日志系统中的最老日志序列号lsn

根据oldest_lsn与log->lsn(current

lsn)之间的差距,判断日志空间是否足够,是否需要进行flush dirty pages操作

读取当前日志系统中最老的Checkpoint Lsn

根据last_checkpoint_lsn与log->lsn之间的差距,判断是否需要向前推进检查点

若需要flush dirty

pages,调用函数log_preflush_pool_modified_pages

log_preflush_pool_modified_pages -> buf_flush_list(ULINT_MAX,

new_oldest)

new_oldest参数,指定当前将dirty pages

flush到何lsn?sync参数指定当前flush操作是否为同步操作?由函数log_checkpoint_margin计算,代码如下:

oldest_lsn = log_buf_pool_get_oldest_modification();

age = log->lsn – oldest_lsn;

if (age > log->max_modified_age_sync) {

sync = TRUE;

advance = 2 * (age – log->max_modified_age_sync);

} else

if (age > log->max_modified_age_async) {

advance = age – log->max_modified_age_async;

} else {

advance = 0;

}

ib_uint64_t new_oldest = oldest_lsn + advance;

if (checkpoint_age > log->max_checkpoint_age) {

checkpoint_sync = TRUE;

do_checkpoint = TRUE;

}

log->max_modified_age_(a)sync; log->max_checkpoint_age

以上参数用于控制是否需要进行log flush,以及是否需要进行Checkpoint。

参数的计算,在log0log.c::log_calc_max_ages函数中完成,代码较为简单,如下所示:

margin = smallest_capacity – free;

margin = margin – margin / 10;

log->log_group_capacity = smallest_capacity;

log->max_modified_age_async = margin-margin / LOG_POOL_PREFLUSH_RATIO_ASYNC;

log->max_modified_age_sync = margin - margin / LOG_POOL_PREFLUSH_RATIO_SYNC;

log->max_checkpoint_age_async = margin-margin/LOG_POOL_CHECKPOINT_RATIO_ASYNC;

log->max_checkpoint_age = margin;

#define

LOG_POOL_CHECKPOINT_RATIO_ASYNC 32

#define

LOG_POOL_PREFLUSH_RATIO_SYNC 16

#define

LOG_POOL_PREFLUSH_RATIO_ASYNC 8

简单来说,margin近似认为是Innodb系统可用的日志空间的9/10;

日志空间消耗超过7/8时,一定要进行异步Flush日志;

日志空间消耗超过15/16时,一定要进行同步Flush日志;

日志空间消耗超过31/32时,一定要进行异步Flush Buffer Pool;

日志空间消耗达到margin上限时,一定要进行同步Flush Buffer Pool

以上判断均在log_checkpoint_margin函数中完成,1S中判断一次。

若需要向前推进检查点,调用函数log_checkpoint,log_checkpoint函数的流程,在前一章节中已经分析。

innodb_flush_method

无论是数据文件,还是日志文件,在完成write操作之后,最后都需要flush到disk。

是否flush?如何进行flush?日志文件与数据文件的flush操作有何不同?通过参数innodb_flush_method控制。

接下来我主要从源码层面简单分析以下innodb_flush_method参数的使用(在MySQL数据库InnoDB存储引擎

5.5-5.6中,此参数的名字修改为innobase_file_flush_method)。

初始化

函数处理流程:

srv0start.cc::innobase_start_or_create_for_mysql

if (srv_file_flush_method_str == NULL) {

srv_unix_file_flush_method = SRV_UNIX_FSYNC;

srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED;

} else if (0 == ut_strcmp(srv_file_flush_method_str, “fsync”)) {

srv_unix_file_flush_method = SRV_UNIX_FSYNC;

} else if (0 == ut_strcmp(srv_file_flush_method_str, “O_DSYNC”)) {

srv_unix_file_flush_method = SRV_UNIX_O_DSYNC;

} else if (0 == ut_strcmp(srv_file_flush_method_str, “O_DIRECT”)) {

srv_unix_file_flush_method = SRV_UNIX_O_DIRECT;

} else if (0 == ut_strcmp(srv_file_flush_method_str, “littlesync”)) {

srv_unix_file_flush_method = SRV_UNIX_LITTLESYNC;

} else if (0 == ut_strcmp(srv_file_flush_method_str, “nosync”)) {

srv_unix_file_flush_method = SRV_UNIX_NOSYNC;

}

根据用户指定的srv_file_flush_method_str的不同,设置srv_unix_file_flush_method的不同取值,innodb内部,通过判断此参数,来确定以何种模式open

file,以及是否flush write。

简单起见,此处只拷贝了linux部分处理代码,未包括windows部分。

open file

Innodb系统启动阶段,设置完成srv_unix_file_flush_method参数之后,可以进行I/O操作,I/O操作的总入口为函数fil0fil.c::fil_io,相信大家已经看过上面的分析之后,对此函数不会陌生。

fil0fil.c::fil_io函数中,处理了file open的过程,函数流程如下:

fil0fil.c::fil_io -> fil_node_perpare_for_io -> fil_node_open_file ->

if (space->purpose == FIL_LOG) {

node->handle = os_file_create(innodb_file_log_key, node->name, OS_FILE_OPEN,

OS_FILE_AIO, OS_LOG_FILE, &ret);

} else

if (node->is_raw_disk) {

node->handle = os_file_create(innodb_file_data_key, node->name,

OS_FILE_OPEN_RAW, OS_FILE_AIO, OS_DATA_FILE, &ret);

} else {

node->handle = os_file_create(innodb_file_data_key, node->name, OS_FILE_OPEN,

OS_FILE_AIO, OS_DATA_FILE, &ret);

}

根据当前文件类型不同,底层依赖的硬件环境不同,调用os_file_create宏定义open对应的文件。os_file_create宏定义对应的函数是os_file_create_func.

os_file_create_func函数处理open file的流程:

Log file将O_DSYNC转化为O_SYNC,O_DSYNC设置只对data file有用

if (type == OS_LOG_FILE && srv_unix_file_flush_method ==

SRV_UNIX_O_DSYNC) {

create_flag = create_flag | O_SYNC;

file = open(name, create_flag, os_innodb_umask);

Data file与O_DIRECT组合,需要禁用底层os file cache

if (type != OS_LOG_FILE && srv_unix_file_flush_method ==

SRV_UNIX_O_DIRECT)

os_file_set_nocache(file, name, mode_str);

flush data

fil0fil.c::fil_io函数打开file之后,可以进行file的write与必要的flush操作,write操作在前面的章节中已经分析,本章主要看srv_unix_file_flush_method参数对于flush操作的影响。

srv_unix_file_flush_method = SRV_UNIX_NOSYNC

无论是log file,还是data file,一定只write,但不flush

srv_unix_file_flush_method = SRV_UNIX_O_DSYNC

Log file: 不flush

if (srv_unix_file_flush_method != SRV_UNIX_O_DSYNC

&& srv_unix_file_flush_method != SRV_UNIX_NOSYNC)

fil_flush(group->space_id);

当然,其他情况下,Log

file是否一定flush?还与参数srv_flush_log_at_trx_commit的设置有关

Data file:

srv_unix_file_flush_method = SRV_UNIX_LITTLESYNC

Data file: 不flush

srv_unix_file_flush_method =

未明之处

innodb_flush_method参数,在使用系统native aio时,好像对于data

file完全无影响,还需要进一步的理解与调研。

Percona版本优化

关于Percona XtraDB的优化,推荐一篇十分好的文章: XtraDB: The Top 10 enhancements [11].

该文详细列举了XtraDB对于原生InnoDB引擎做的最重要的10个优化,虽然文章是2009年8月写的,但是主要优化都已经存在了,每一个都值得一读。

当然,在本文中,我接下来主要讨论XtraDB在Checkpoint与Insert

Buffer两个方面做的优化。Checkpoint与Insert

Buffer优化,都属于XtraDB优化中的一个大类:I/O优化,可见网文: Improved

InnoDB I/O Scalability [12].

增加innodb_io_capacity选项。原生innodb中的参数srv_io_capacity,写死的是200,XtraDB中增加此

选项,用户可以根据系统的硬件不同而设置不同的io_capacity。但是,io_capacity与系统的实际I/O能力还是有所区别,网文与其中的

讨论: MYSQL 5.5.8 and Percona Server: being adaptive

[13]给出了fusion-io下,innodb_io_capacity选项具体如何设置更为合理。

源代码,参考的版本包括Percona-Server-5.5.15-rel21.0;

Percona-Server-5.5.18-rel23.0; Percona-Server-5.1.60;

Flush & Checkpoint优化

XtraDB对于Flush &

Checkpoint的优化,主要在于新增了系统变量:innodb_adaptive_checkpoint

此变量可设置的值包括:none, reflex, estimate,

keep_average,分别对应于0/1/2/3;同时改变量要与Innodb自带的innodb_adaptive_flushing变量配合使用

关于每种设置的不同含义,[12]中有详尽介绍,此处给出简单说明:

none

原生innodb adaptive flushing策略

reflex

与innodb基于

innodb_max_dirty_pages_pct的flush策略类似。不同之处在于,原生innodb是根据dirty

pages的量来flush;而此处根据dirty

pages的age进行flush。每次flush的pages根据innodb_io_capacity计算

estimate

与reflex策略 类似,都是基于dirty

page的age来flush。不同之处在于,每次flush的pages不再根据innodb_io_capacity计算,而是根据[number

of modified blocks], [LSN progress speed]和[average age of all

modified blocks]计算

keep_average

原生Innodb每1S触发一次dirty page的flush,此参数降低了flush的时间间隔,从1S降低为0.1S

注: 在最新的Percona

XtraDB版本中,reflex策略已经被废弃;estimate,keep_average策略的算法,或多或少也与网文中提到的有所出入,应该是算法优化后的结果,具体算法参考以下的几个小章节。

reflex

此策略,Percona XtraDB

5.1.60版本中存在,但是在5.5版本中被删除,源代码级别彻底删除,可能并无太多的意义,功能与estimate重合,不建议使用。

estimate

函数处理流程:

// 1.

innodb_adaptive_checkpoint参数必须与innodb_adaptive_flushing同时设置

if (srv_adaptive_flushing &&

srv_adaptive_flushing_method == 1)

// 2. 获取当前最老dirty page的lsn

oldest_lsn = buf_pool_get_oldest_modification();

// 3. 若当前未flush的日志量,超过Checkpoint_age的1/4,则进行flush

if ((log_sys->lsn) – oldest_lsn) >

(log_sys->max_checkpoint_age/4)

// 4. estimate flush策略

遍历buffer pool的flush_list链表,统计以下信息

n_blocks: 链表中的page数量

level: 链表所有page刷新的紧迫程度的倒数

level += log_sys->max_checkpoint_age –

(lsn – oldest_modification);

最新修改的page,level贡献越大,紧迫程度越小;越老的page,紧迫程度越大。

关于log_sys->max_checkpoint_age的功能,可参考 Checkpoint

Info更新-流程二 章节。

需要flush的dirty pages数量bpl,计算公式如下:

bpl = n_blocks * n_blocks * (lsn – lsn_old) / level;

其中:lsn_old为上一次flush时记录下的lsn

调用buf_flush_list函数,进行flush

buf_flush_list(bpl, oldest_lsn + (lsn – lsn_old));

keep_average

keep_average策略,将原生的Innodb,每1S flush一次dirty pages,改为每0.1S做一次。

if (srv_adaptive_flushing &&

srv_adpative_flushing_method == 2)

next_itr_time -= 900;

MySQL数据库InnoDB存储引擎,每次将netx_itr_time加1000ms,然后sleep这1000ms时间。进入keep_average策略,将next_itr_time减去900,那么下一次也就只会sleep

100ms时间。

接下来则是分析keep_average策略如何计算当前需要flush多少dirty

pages。下图能够较为清晰的说明keep_average策略:

a4c26d1e5885305701be709a3d33442f.png

图中名词解释:

prev_flush_info.count

上一次flush前,buffer pool中的dirty pages数量

new_blocks_sum

上次记录prev_flush_info.count之后,系统新产生的dirty pags

blocks_sum

当前系统,buffer pool中的dirty pages数量

flushed_blocks_sum

flushed_blocks_sum = new_blocks_sum + prev_flush_info.count –

blocks_sum;

上次的flush数量+循环间其余flush的数量

Next Round

本次flush dirty pages前,记录新的prev_flush_info.count = blocks_sum

n_pages_flushed_prev

此参数未标出,表示上次keep_average策略成功flush了多少dirty pages

计算本次应该flush的量:

n_flush = blocks_sum * (lsn – lsn_old) /

log_sys->max_modified_age_async;

公式分析:

系统中的dirty pages,有多少比率需要在此时被flush

log_sys->max_modified_age_async

日志异步flush的临界值,若当前系统的lsn间隔大于此值,则启动异步flush。

此参数为原生Innodb所有,Percona此处借用来计算。

关于log_sys->max_modified_age_async参数在Innodb中的作用及设置,

flush量微调:

if (flushed_blocks_sum > n_pages_flushed_prev)

n_flush -= (flushed_blocks_sum – n_pages_flushed_prev);

若flushed_blocks_sum >

n_pages_flushed_prev,两次之间的实际flush量大于

上次keep_average的flush量,那么本次keep_average需要flush量应相应减少。

MySQL 5.6.6 Flushing优化

InnoDB自带的flushing策略有问题,Percona的XtraDB对其做了优化,提出了estimate与keep_average两

种新的flushing策略。在MySQL 5.6.6-labs版本中,Oracle

InnoDB团队提出了自己的新的flushing算法[16],不同于已有的Percona算法,以下对此新算法作简要分析。关于新flushing算

法的测试结果,可见[14][15]。

首先,在MySQL 5.6-labs版本中,dirty

pages的flushing操作,从InnoDB主线程中移出,新开一个buf_flush_page_cleaner_thread

(page_cleaner)线程来进行。仍旧是每次休眠1s,然后进行一次flushing尝试。

处理流程

新的flushing算法的处理流程如下:

buf0flu.cc::buf_flush_page_cleaner_thread();

// 回收buffer pool LRU链表,此处不考虑

page_cleaner_flush_LRU_tail();

// 根据用户指定的参数,判断是否需要进行dirty pages的flushing

// 每1S调用一次此函数

page_cleaner_flush_pages_if_needed();

// 根据用户指定的innodb_flushing_avg_loops参数(默认取值为30),

// 计算前innodb_flushing_avg_loops个flushing的平均速度

// 1. avg_page_rate:

平均的dirty

pages的flushing速度

// 2.

lsn_avg_rate: 平均的日志产生速度

if (++n_iterations >= srv_flushing_avg_loops)

// 计算目前系统中的最老未flush的dirty page的日志年龄

age = cur_lsn – oldest_lsn;

// 根据系统中的脏页数量,计算本次需要flushing的页面数量:

// 1. 计算系统中脏页面占用的比率[0, 100]

// 2. 若用户未指定脏页的lower water mark –

innodb_max_dirty_pages_pct_lwm

// [0, 99]默认值为50. 则采用原有的srv_max_buf_pool_modified_pct参数判断

// 超过此参数则返回100.

// 3. 若用户指定了lower water mark,并且脏页比率超过此值,则返回

// dirty_pct * 100 / (srv_max_buf_pool_modified_pct + 1);否则返回0

//

// 注意:

//

根据innodb_max_dirty_pages_pct_lwm与innodb_max_buf_pool_modified_ptc

// 两参数的设置情况,最终的返回值主要与后者相关,后者设置的越小,计算出

// 的flushing量越大,甚至会超过100 (超过innodb_io_capacity)。但是,由于后者

// 默认设置为75,因此在默认设置下,返回值的范围是[0, 132],一次flush的量,

// 并不会比innodb_io_capacity多多少。

pct_for_dirty = af_get_pct_for_dirty();

// 根据系统中最老日志的年龄,计算本次需要flushing的页面数量:

// 1. 根据系统参数innodb_adaptive_flushing_lwm,默认取值为10,区间为[0, 70]

// 计算对应的lower water mark

// lsn age: af_lwm = (srv_adaptive_flushing_lwm * log_get_capacity())

/ 100

// 2. 若当前最老日志的年纪小于lower water mark age,则不需要根据日志flushing

// 3. 获得系统的异步日志刷新阀值:max_async_age,此值的具体含义可见 3.4.1.2

// 章节,近似等于日志空间的7/8

// 4. 若当前系统的日志年纪小于异步刷新阀值,并且系统参数

// innodb_adaptvie_flushing未开启,则不需要根据日志flushing

// 5. 不满足以上条件,需要根据日志进行flushing,返回值pct_for_lsn的计算如下:

//

lsn_age_factor

= (age * 100) / max_async_age; 取值区间近似为(0, 114]

// pct_for_lsn =

srv_max_io_capacity

/ srv_io_capacity

// *

(lsn_age_factor * sqrt(lsn_age_factor)) / 7.5;

// pct_for_lsn的取值范围近似为(0, 600]

// 其中,innodb_max_io_capacity参数为硬件能够支撑的最大IOPS,默认值

// 4000,innodb_io_capacity默认值为400

// 注意:

// 1.基于日志的flushing,一次flushing的速度与日志的产生速度正相关,

//日志产生的速度越快,需要flushing的dirty pages数量也越多,速度也更快。

// 2. 基于日志的flushing,其返回值有可能超过100,也就是一次flush的量

// 超过innodb_io_capacity,甚至是超过innodb_max_io_capacity的系统参数。

// 3. 在默认参数环境下,基于日志的flush策略,其速度有可能远远大于基于

// dirty pages的策略。其主要目的是为了保证日志回收足够快,从而不至于出现

// 由于日志空间不足而导致的async甚至是sync flushing出现。

pct_for_lsn = af_get_pct_for_lsn(age);

// 真正需要flushing的页面数量,是根据脏页数量/日志年龄 计算出来的

// 本次flushing页面数量的较大值

pct_total = ut_max(pct_for_dirty, pct_for_lsn);

// 根据本次计算出来的flushing页面数量,与上次flush的平均速度,再次

// 取平均值,获得最终需要flushing的页面数量

n_pages = (PCT_IO(pct_total) + avg_page_rate) / 2;

// 当然,需要根据用户设置的innodb_max_io_capacity参数,进行一次微调

// 保证一次flushing的页面数量,不会超过硬件IO能力的处理上限

if (n_pages > srv_max_io_capacity)

n_pages = srv_max_io_capacity;

// 开始进行本次真正的flushing操作

page_cleaner_do_flush_batch();

新增参数

MySQL

5.6.6-labs版本中,针对新的flush策略,新增了如下几个参数,具体参数的功能及意义,在上面的流程分析中已经详细给出。

innodb_adaptive_flushing_lwm

innodb_max_dirty_pages_pct_lwm

innodb_max_io_capacity

innodb_io_capacity

innodb_flushing_avg_loops

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值