MySQL · 效能最佳化· 5.7.6 InnoDB page flush 最佳化

來源:互聯網
上載者:User

MySQL · 效能最佳化· 5.7.6 InnoDB page flush 最佳化

在這篇文中,我們已經詳細介紹了Oracle MySQL以及社區分支最新的對InnoDB page flush的最佳化。在最近release的5.7.6版本中又有了進一步的改進。主要包括以下幾點修改


修改一、更精確的loop時間

Page cleaner每做srv_flushing_avg_loops次flush後,會去計算刷髒和Redo LSN增長的速度。由於每次Page cleaner的工作量是自適應的,一次flush操作的時間可能超過1秒。

在新版本中,統一採用目前時間和上次更新速率的時間差來確認是否需要重新計算速率。因此參數innodb_flushing_avg_loops的行為實際上等同於每這麼多秒後重計算速率。


修改二、根據buffer pool執行個體的髒頁分布來決定刷髒

從5.7版本開始支援配置多個page cleaner線程以實現並行刷髒。在5.7.6之前的版本,Page cleaner協調線程根據當前的負載情況,會計算出預計需要flush的總page數和目標LSN,然後在多個bp instance間做個均分。

但是考慮一種情境:如果bp執行個體間的負載不平衡,某個執行個體在目標LSN之前的髒頁很多,而有些執行個體很少,那麼本應該多做刷髒動作的bp就可能產生堆積。 我們之前在webscalesql google公開討論群組 有過類似的討論,感興趣的可以看看。

回到正題上來,在5.7.6版本中,計算目標page數的方法大概如下:

  • 根據當前髒頁佔比和Redo LSN增長狀態,計算利用IO Capacity的百分比(pct_total)
  • 計算目標LSN:
 target_lsn = oldest_lsn + lsn_avg_rate * buf_flush_lsn_scan_factor

其中oldest_lsn表示當前buffer pool中最老page的LSN,lsn_avg_rate表示每秒LSN推進的平均速率,buf_flush_lsn_scan_factor目前是hardcode的,值為3。

  • 統計每個buffer pool 小於target_lsn的page數pages_for_lsn

初步估定每個bp instance 的n_pages_requested= pages_for_lsn /buf_flush_lsn_scan_factor。每個bp的pages_for_lsn被累加到sum_pages_for_lsn

  • 同時根據io capacity估算總的需要flush的Page數量:
sum_pages_for_lsn /= buf_flush_lsn_scan_factor;n_pages = (PCT_IO(pct_total) + avg_page_rate + sum_pages_for_lsn) / 3;

n_pages若超過innodb_io_capacity_max,則設定為innodb_io_capacity_max

  • 輪詢每個Buffer pool 執行個體:
如果當前有足夠的Redo 空間:n_pages_requested  = n_pages / srv_buf_pool_instances否則:n_pages_requested = n_pages_requested  * n_pages / sum_pages_for_lsn

也就是說,在Redo 空間足夠時,依然採用均衡的刷髒邏輯。


在早期版本中,會根據兩個條件來判斷每個bp刷髒的進度:目標LSN及page數。而到了5.7.6版本裡,大多數情況下只根據更加準確的請求刷page數來進行判定 (系統空閑時進行100% io capactiy的page flush、崩潰恢複時、以及執行個體shutdown時的刷髒除外)

雖然計算公式比較清晰,但有些factor的定值依然讓人很困惑,也許是官方測試的比較理想的配置。不過最好還是設定成可配置的,由有經驗的使用者根據自己具體的負載情況來進行定製。

 

修改三、使用者線程在檢查Redo 空間時不參與刷髒

在之前版本中,當未做checkpoint的日誌量過多時,使用者線程會進行batch flush操作,將每個buffer pool instance的LSN推進到某個指定值。如果某個bp instance已經有別的線程在flush,則跳過嘗試下一個instance,同時認為這次的flush操作是失敗的,會返回重試。

當使用者線程參與到刷髒時,通常會認為這是個效能拐點,TPS會出現急劇下降,大量線程陷入condtion wait 和並發flush。因此在5.7.6裡,當使用者線程需要推進LSN時,不再主動發起刷髒,這些工作會留給page cleaner線程來作。 使用者線程只去輪詢每個bp instance,直到所有的bp instance 的LSN超過其目標LSN,每次輪詢預設sleep重試時間為10000微妙

事實上, Percona Server早在5.6版本裡已經使用相同的策略了。

 

修改四、為page cleaner線程設定更高的優先順序

在Linux平台下,對於page cleaner的協調線程和worker線程,其CPU優先順序被設定為-20,即最高優先順序,通過函數set_priority設定。目前還不支援參數配置。

 

修改五、防止checkpoint LSN被覆蓋

在之前的版本中,儘管每次在寫Redo時都會去檢查記錄檔是否容留了足夠百分比的可用空間,但實際上並沒有考慮即將寫入的Redo log長度。如果我們操作一些極大的記錄併產生很長的Redo log記錄,這可能導致檢查點LSN被覆蓋掉,如果這時候crash就會無法安全的做崩潰恢複。

在新的邏輯裡,在檢測到當前寫入的Redo 可能造成覆蓋上次的checkpoint點時,就會進入sleep,等待page cleaner線程刷髒,然後再做一次Redo log checkpoint。如此迴圈直到checkpoint的LSN推進到安全的位置。


參考: worklog:wl#7868,及補丁

本文永久更新連結地址:

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.