Mysql初探:記憶體資料刷盤機制
此文為極客時間:MySQL實戰45講的12節的學習筆記
一、mysql 的刷盤機制
而之前提到過,mysql 使用了 WAL 技術,即更新的時候先更新記憶體中的資料,然後必要的時候再將記憶體中的資料刷入磁碟。我們把記憶體中這些被修改過,跟磁碟中的資料頁不一致的資料頁稱為髒頁。
其中,有四種情況會觸發髒頁的刷盤:
- redo log 可寫空間滿了。
- 記憶體滿了,需要淘汰的資料頁恰好是髒頁。
- 系統不繁忙的時候。
- 關閉資料庫的時候。
其中,第三種情況不會為系統帶來過多影響的,第四中情況下不會在乎為系統帶來的影響。所以我們只需要關注第一和第二種情況:
對於第二種情況,由於 mysql 的更新需要先寫日誌,所以當日志滿了的情況下,所有的更新都會停止,一直到刷完盤日誌騰出了空間為止
而對於第二種情況,當查詢的資料在記憶體中的資料頁沒有的時候,就需要淘汰舊頁釋放記憶體以讀入新頁,所以當一次查詢導致需要淘汰的髒頁過多的時候,就需要先等待較長的刷盤時間,然後才能獲取響應。
為了避免上述兩種情況,必須要控制髒頁在記憶體中的比例。
二、刷髒頁的控制策略
首先,我們必須要知道主機磁碟的寫入能力有多強,這樣 innodb 才可以知道它刷髒頁的速度最快應該是多快。
我們可以通過設定 innodb_io_capacity
這個引數來告訴 innodb 磁碟的寫入速度。這個引數的值不宜過小,因為這會導致 innodb 錯誤的估計刷盤速度,最後導致刷髒頁的速度跟不上髒頁生成的速度。
innodb_io_capacity
引數 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)
innodb_io_capacity
定義的能力乘以 R% 來控制刷髒頁的速度。
這一整個流程對應的圖片是這樣的:
所以,我們需要關注記憶體中的髒頁比例,讓它儘量不要到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
關閉預設的重新整理相鄰髒頁的策略。