1. 程式人生 > 資料庫 >Mysql初探:記憶體資料刷盤機制

Mysql初探:記憶體資料刷盤機制

此文為極客時間:MySQL實戰45講的12節的學習筆記

一、mysql 的刷盤機制

而之前提到過,mysql 使用了 WAL 技術,即更新的時候先更新記憶體中的資料,然後必要的時候再將記憶體中的資料刷入磁碟。我們把記憶體中這些被修改過,跟磁碟中的資料頁不一致的資料頁稱為髒頁。

其中,有四種情況會觸發髒頁的刷盤:

  1. redo log 可寫空間滿了。
  2. 記憶體滿了,需要淘汰的資料頁恰好是髒頁。
  3. 系統不繁忙的時候。
  4. 關閉資料庫的時候。

其中,第三種情況不會為系統帶來過多影響的,第四中情況下不會在乎為系統帶來的影響。所以我們只需要關注第一和第二種情況:

對於第二種情況,由於 mysql 的更新需要先寫日誌,所以當日志滿了的情況下,所有的更新都會停止,一直到刷完盤日誌騰出了空間為止

而對於第二種情況,當查詢的資料在記憶體中的資料頁沒有的時候,就需要淘汰舊頁釋放記憶體以讀入新頁,所以當一次查詢導致需要淘汰的髒頁過多的時候,就需要先等待較長的刷盤時間,然後才能獲取響應

為了避免上述兩種情況,必須要控制髒頁在記憶體中的比例。

二、刷髒頁的控制策略

首先,我們必須要知道主機磁碟的寫入能力有多強,這樣 innodb 才可以知道它刷髒頁的速度最快應該是多快。

我們可以通過設定 innodb_io_capacity 這個引數來告訴 innodb 磁碟的寫入速度。這個引數的值不宜過小,因為這會導致 innodb 錯誤的估計刷盤速度,最後導致刷髒頁的速度跟不上髒頁生成的速度。

innodb_io_capacity

規定了刷髒頁速度的極限,但是實際上磁碟不可能只服務這麼一個功能,所以還需要參考 redo log 的刷盤速度允許的記憶體中的髒頁比例。

引數 innodb_max_dirty_pages_pct 是髒頁比例上限,預設值是 75%。innodb 會根據當前的髒頁比例(假設為 M),算出一個範圍在 0 到 100 之間的數字,這個公式是 F1(M)

而每次寫入 redo log 的寫入點 wp 都會有一個序號,innodb 會根據這個序號和上一次清理日誌的界限 cp 之間的差值——我們假設為 N——計算得到一個範圍在 0 到 100 之間的數字,這個公式是 F2(N)

根據上述算得的 F1(M)F2(N)

兩個值,取其中較大的值記為 R,之後引擎就可以按照 innodb_io_capacity 定義的能力乘以 R% 來控制刷髒頁的速度。

這一整個流程對應的圖片是這樣的:

image-20201029164736099

所以,我們需要關注記憶體中的髒頁比例,讓它儘量不要到75%,並且合理的設定 innodb_io_capacity 引數。

其中,針對髒頁的比例,我們可以通過 Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total去設定。

另外,由於 mysql 存在這樣一個機制:如果要刷盤的髒頁相鄰的資料頁恰好也是髒頁,就一起寫入磁碟,如果鄰居的鄰居也是如此。在機械硬碟時代這個策略可以減少隨機IO,但是如果使用固態硬碟的話隨機IO的效能往往比較高,所以使用這個策略反而拖累了查詢效能。因此可以通過 innodb_flush_neighbors關閉這個“連坐”的策略。

三、總結

innodb 有四種情況會觸發髒頁的刷盤:

  • redo log 可寫空間滿了;
  • 記憶體滿了,需要淘汰的資料頁恰好是髒頁;
  • 系統不繁忙的時候;
  • 關閉資料庫的時候。

innodb 通過的刷盤速度通過類似這樣的公式計算:

innodb_io_capacity * Max( F(innodb_max_dirty_pages_pct), F(redo log的wp - redo log的cp) )

其中,innodb_io_capacity表示磁碟的最大IO能力;innodb_max_dirty_pages_pct表示允許髒頁在記憶體中的佔比,預設值為75%;

當使用固態硬碟的時候,可以設定innodb_flush_neighbors關閉預設的重新整理相鄰髒頁的策略。