技術分享 | show engine innodb status中Pages flushed up to 的含義

愛可生雲資料庫發表於2021-09-26

作者:胡呈清

愛可生 DBA 團隊成員,擅長故障分析、效能優化,個人部落格:https://www.jianshu.com/u/a95...,歡迎討論。

本文來源:原創投稿

*愛可生開源社群出品,原創內容未經授權不得隨意使用,轉載請聯絡小編並註明來源。


有一個很久前就存在的疑惑:
在沒有寫入的情況下,show engine innodb status 中的 Pages flushed up to 為什麼不等於 Last checkpoint point?它表示什麼?

今天在寫一篇文章時,想通過一個測試,從這幾個 LSN 的變化來驗證一個說法,結果重新勾起了這個問題,在一番“研究”後(其實就是google了一通,當然還是需要一些測試驗證),終於弄明白了其中含義。

主要還是借鑑了一篇文章:http://blog.itpub.net/3022142...,因為有大量的原始碼分析,而我看不懂原始碼,所以花了不少時間才理解其中原理,並且通過測試驗證了其準確性,然後整理成了一個讓像我這樣不懂程式碼的人更方便閱讀的文件。

今天在寫一篇文章時,想通過一個測試,從這幾個 LSN 的變化來驗證一個說法,結果重新勾起了這個問題,這次我決定徹底弄明白到底是怎麼一回事。

主要還是借鑑了一篇文章:http://blog.itpub.net/3022142...,因為有大量的原始碼分析,而我也看不懂原始碼,所以花了不少時間才理解其中原理,並且通過測試驗證了其準確性,然後整理成了一個更方便讓像我這樣不懂程式碼的人理解的文件。

LSN

show engine innodb status 的輸出中,有一部分是 LSN 的狀態:

mysql> pager grep -A 5 LOG                                      
PAGER set to 'grep -A 5 LOG'
mysql> show engine innodb status\G
LOG
---
Log sequence number 2471197058
Log flushed up to   2471197058
Pages flushed up to 2471197058
Last checkpoint at  2471197049
1 row in set (0.00 sec)

Log sequence number:所有修改資料的操作都會產生 redo log,這是系統當前 redo log 序列號(後面簡稱 LSN)的最大值;

Log flushed up to:當前已經刷盤的 redo log 的序列號;

Pages flushed up to:討論的重點;

Last checkpoint at:最後一次 checkpoint 的位置。

Pages flushed up to 到底表示什麼?最常見的說法就是髒頁重新整理到磁碟的 LSN,但 Last checkpoint at 也表示在此之前的資料頁已經刷盤,而且通常我們看到的 Pages flushed up to 總是比 Last checkpoint at 大 ,所以這個說法肯定是錯誤的。

根據參考文章中的原始碼分析,Pages flushed up to 的取值邏輯是:

Pages flushed up to 取的是所有 buffer pool instance 中的 flush list 中最大 oldest modification lsn 頁中的帶有最小的 oldest modification lsn 的值(這裡可能有點難以理解,我們可以簡化理解為取 flush list 中最大的 oldest modification lsn);

如果取到的 oldest modification lsn 為0,意味著沒有髒頁,那麼我們就取 log_sys->lsn 的值,即 show engineinnodb status 顯示的 Log sequence number。

LSN 更新的邏輯

取 Pages flushed up to 的目的是什麼?因為是取的 flush list 中髒頁的最大 LSN,接下來做 checkpoint 時,可以用作這次刷髒的一個結束位置。

在一個正常執行的 MySQL 中,系統 LSN 隨著 SQL 的執行(修改資料的SQL)不斷增大(實時的),Pages flushed up to 值也會按某個頻率獲取更新,所以 Pages flushed up to 一般會落後於系統 LSN。然後 InnoDB master thread 每秒和每十秒做 checkpoint 時(還有其他的機制觸發 checkpoint,這裡不考慮並不影響理解),在將髒頁刷盤後會將 Last checkpoint at 的值更新成 Pages flushed up to,由於 Pages flushed up to 在不斷更新,所以我們觀察到的 Last checkpoint at 一般會小於 Pages flushed up to。

在沒資料寫入的情況下,為什麼 Last checkpoint point 不等於 Pages flushed up to?

是因為做 checkpoint 時同時 redo 日誌會寫 MLOG_CHECKPOINT,而 MLOG_CHECKPOINT 佔用9個位元組,所以系統 LSN 會加9,而由於髒頁都被刷盤了,flush list 為空,獲取 Pages flushed up to 時會直接取系統 LSN 值,所以也會比 Last checkpoint point 大 9。

獲取 Pages flushed up to 和 checkpoint 不是一個原子操作,它是在 checkpoint 前就獲取了,指的是下一次 checkpoint 結束的位置。

測試驗證

我們手工開啟一個事務寫入一行資料(不提交),會發現如下圖所示:

  • Log sequence number 增加了,因為系統 LSN 是實時產生的;
  • Log flushed up to 沒變,說明 redo log 還沒刷盤(也可能觀察到這個值增加並且和 Log sequence number 一致,因為 InnoDB 後臺執行緒每秒會刷 redo log,未提交事務的 redo log 可能提前刷盤);
  • Pages flushed up to 沒變,因為這個值不是實時產生的,只要我們手速夠快,在執行完 insert 後立刻檢視 LSN,就可以看到這個值不變;
  • Last checkpoint point 沒變,同樣的只要手速夠快,在 checkpoint 前檢視到的值就不會變。

我們隔幾秒鐘後再檢視 LSN,會發現:所有值都變了,並且前 3個值一樣,Last checkpoint point 比它們的值小 9。這是因為InnoDB Master Thread 每秒、每十秒都會做 checkpoint,所有髒頁都刷盤後,flush list 為空,符合我們前面所說的原理:

在持續寫入的情況下,是可以觀察到 Last checkpoint point 等於 Pages flushed up to 的(checkpoint 後還沒有獲取新的 Pages flushed up to):

相關文章