天天看點

[MySQL 5.6] Innodb page cleaner線程重新整理政策

這部分内容是從http://mysqllover.com/?p=512 剝離出來,原文中為了保持整潔,将這些内容删除。

有以下幾個參數會影響到page cleaner的行為:

innodb_lru_scan_depth

innodb_adaptive_flushing_lwm

innodb_max_dirty_pages_pct_lwm

innodb_io_capacity_max

innodb_flushing_avg_loops

在函數page_cleaner_flush_pages_if_needed中會确定三個影響刷髒頁行為的變量

1.    根據redo log計算比例(pct_for_lsn),當小于innodb_adaptive_flushing_lwm時,pct_for_lsn值為0,當小于異步刷redo的比例(log_sys->max_modified_age_async)時且關閉選項innodb_adaptive_flushing時,pct_for_lsn也為0,否則,計算:

((innodb_io_capacity_max/innodb_io_capacity)

*(lsn_age_factor * sqrt((double)lsn_age_factor)))/7.5

其中lsn_age_factor為目前的(redo比例*100)/max_modified_age_async

2.    根據髒頁計算比例(pct_for_dirty),當innodb_max_dirty_pages_pct_lwm設定為0時,和以前的行為類似,如果髒頁比例大于innodb_max_dirty_pages_pct時,pct_for_dirty設定為100,否則如果髒頁比大于innodb_max_dirty_pages_pct_lwm,pct_for_dirty值為

(dirty_pct * 100)/( innodb_max_dirty_pages_pct+1)

3.    最近innodb_flushing_avg_loops次平均刷髒頁的數量,同時還考慮上次統計時候的平均數量,再除以2

avg_page_rate= ((sum_pages / srv_flushing_avg_loops) + avg_page_rate) / 2

另外也會計算lsn的重新整理速率

lsn_rate= (cur_lsn – prev_lsn) / srv_flushing_avg_loops;

lsn_avg_rate= (lsn_avg_rate + lsn_rate) / 2;

然後根據上述兩個值計算要重新整理的page數:

pct_total = ut_max(pct_for_dirty, pct_for_lsn);

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

if (n_pages > srv_max_io_capacity) {

n_pages =srv_max_io_capacity;

}

除了髒頁的數量外,還要确定一個lsn下限值(lsn_limit),oldest_modification小于lsn_limit的block需要被重新整理掉,其計算方式也受參數innodb_flushing_avg_loops影響:

每innodb_flushing_avg_loops次循環,計算

lsn_rate = (cur_lsn – prev_lsn) /srv_flushing_avg_loops;

lsn_avg_rate = (lsn_avg_rate + lsn_rate) / 2;

lsn_avg_rate表示lsn最近的平均推進速率

然後計算lsn_limit:

if (last_pages && cur_lsn – last_lsn >lsn_avg_rate / 2) {

age_factor= prev_pages / last_pages;

lsn_limit = oldest_lsn + lsn_avg_rate * (age_factor +1)

prev_pages表示上一次重新整理時,試圖刷的page數,last_pages表示上次實際重新整理的page數,age_factor總是大于等于1的。

oldest_lsn表示目前bp中的最老lsn.

在确定了需要重新整理的page數及哪些page需要被重新整理後,就可以調用函數page_cleaner_do_flush_batch-> buf_flush_list做實際的操作了。

innodb_flush_log_at_timeout #每隔這麼多秒刷一次日志,隻有在innodb_flush_log_at_trx_commit=2時才生效.在master線程中判斷,見函數srv_sync_log_buffer_in_background,在兩個函數中會調用:

1.srv_master_do_active_tasks

2.srv_master_do_idle_tasks

從命名也可以了解,master線程在系統繁忙及空閑時,都會去做判斷。在5.6的master線程函數srv_master_thread中,每sleep 1秒,會根據目前的系統負載是否繁忙去調用上面這兩個函數,相比之前的函數,master線程函數要清爽很多了。每隔innodb_flush_log_at_timeout秒,會調用log_buffer_sync_in_background(true)去刷日志。

繼續閱讀