天天看點

MySQL怎麼緩解寫的壓力?--- change buffer

想要優化寫的速度,我們首先會想到什麼?

随機IO轉為順序IO,單次寫轉為批次寫。

緩存

常見的寫邏輯優化,先寫緩存,然後刷盤。

邏輯:

  • 如果頁在記憶體中,直接修改。如果不在,讀到記憶體,再修改。
  • 定期刷盤。

資料一緻性

如果命中了緩存,讀到的是準确的。記憶體淘汰的時候,刷盤了,再讀磁盤的時候資料也是準确的。

問題

這樣有兩個問題:

  • 寫多讀少,就會導緻命中緩存的機率比較低,每次都要先讀到記憶體。
  • 如果崩潰了,記憶體的資料就丢了。

redolog

Innodb建立了redolog,即預寫日志。寫記憶體不變,添加了一步寫redolog的步驟。刷盤的時候就把日志清掉。如果崩潰了,就從日志讀取。

WAL技術,WAL的全稱是Write-Ahead Logging,它的關鍵點就是先寫日志,再寫磁盤。

redolog裡面存的是結果值。也就是将change buffer同步到日志了。(binlog寫的是流水日志)

這樣就轉化成了一次讀磁盤,一次寫記憶體操作和一次追加日志寫的操作,都挺快。

change buffer

還有個問題就是寫必須先讀。

我們将更新的資料存到change buffer中,有人讀則将讀到的資料和change buffer中的資料一起傳回。刷盤的時候将資料marge後刷盤。

這樣就優化成了一次寫記憶體+一次日志追加寫。

但是要注意:

不支援唯一索引頁。為什麼?我不讀盤怎麼知道你有沒有沖突呢?

什麼時候刷盤?

  • 系統記憶體滿了。
  • MySQL比較閑
  • 正常關閉

這些都比較好了解。

還有個下面的幾種:

redolog寫滿了。

注意redolog不是無限寫的,而是一個圈。

MySQL怎麼緩解寫的壓力?--- change buffer
  • write pos是目前記錄的位置,一邊寫一邊後移,寫到第3号檔案末尾後就回到0号檔案開頭。
  • checkpoint是目前要擦除的位置,也是往後推移并且循環的,擦除記錄前要把記錄更新到資料檔案。
  • write pos和checkpoint之間的是還空着的部分,可以用來記錄新的操作。
  • 如果write pos追上checkpoint,表示滿了,這時候不能再執行新的更新,得停下來先擦掉一些記錄,把checkpoint推進一下。

定期重新整理髒頁或者LRU淘汰髒頁

記憶體和磁盤資料一緻的,稱為幹淨頁;反正,稱為髒頁。将記憶體資料寫入磁盤,則便一緻,稱為刷髒頁。

兩種坑:

  • 某個查詢需要重新整理過多髒頁,則很慢。
  • redolog寫滿,所有更新都會卡住。

那麼,怎麼提高刷髒頁的效率?

  • 正确地設定innodb_io_capacity參數,判斷寫盤速度。
  • 髒頁比例,innodb_max_dirty_pages_pct。
MySQL怎麼緩解寫的壓力?--- change buffer

在準備刷一個髒頁的時候,如果這個資料頁旁 邊的資料頁剛好是髒頁,就會把這個“鄰居”也帶着一起刷掉;而且這個把“鄰居”拖下水的邏輯還 可以繼續蔓延。

innodb_flush_neighbors 參數,為0就是隻刷自己。

疑惑

很多人可能會問,到底是從redolog刷到磁盤,還是從記憶體刷到磁盤。

回到redolog建立的原因,是為了異常崩潰的時候。

是以正常刷盤是從記憶體刷到磁盤,redolog滿了也是從記憶體刷到磁盤然後清理redolog。異常崩潰呢?也是從redolog寫到記憶體中,先恢複現場,再走正常流程。

結語

  • 如果有不對的地方歡迎指正。
  • 如果有不了解的地方歡迎指出我來加栗子。
  • 如果感覺OK可以點贊讓更多人看到它。

相關閱讀:

  • 學MySQL的第一座大山—索引
  • 學MySQL的第二座大山—鎖,事務
  • 學習mysql的最後一座大山—表設計
  • MySQL為什麼要用B+樹?
  • MySQL怎麼緩解讀的壓力的?—buffer pool
  • MySQL怎麼緩解寫的壓力?— change buffer
  • MySQL架構概覽