Mysql知識延展(五)Redo Log日誌

前言

InnoDB 有兩塊非常重要的日誌,一個是undo log,它用來保證事務的原子性以及InnoDB的MVCC,另外一個就是是redo log,它用來保證事務的持久性

InnoDB記錄了對數據文件的物理更改,並保證總是日誌先行,也就是所謂的WAL,即在持久化數據文件前,保證之前的redo日誌已經寫到磁盤。

LSN(log sequence number) 用於記錄日誌序號,它是一個不斷遞增的 unsigned long long 類型整數。在 InnoDB 的日誌系統中,LSN 無處不在,它既用於表示修改髒頁時的日誌序號,也用於記錄checkpoint,通過LSN,可以具體的定位到其在redo log文件中的位置。

爲了管理髒頁,在 Buffer Pool每個instance上都維持了一個flush list,flush list 上的 page 按照修改這些 page 的LSN號進行排序。因此定期做redo checkpoint點時,選擇的 LSN 總是所有 bp instance 的 flush list 上最老的那個page(擁有最小的LSN)。由於採用WAL的策略,每次事務提交時需要持久化 redo log 才能保證事務不丟。而延遲刷髒頁則起到了合併多次修改的效果,避免頻繁寫數據文件造成的性能問題。

本文的分析基於最新的MySQL 5.7.7-RC版本。

Redo log

InnoDB的redo log可以通過參數innodb_log_files_in_group配置成多個文件,另外一個參數innodb_log_file_size表示每個文件的大小。
因此總的redo log大小爲innodb_log_files_in_group * innodb_log_file_size。

Redo log文件以ib_logfile[number]命名,日誌目錄可以通過參數innodb_log_group_home_dir控制。Redo log 以順序的方式寫入文件,寫滿時回溯到第一個文件,進行覆蓋寫。(但在做redo checkpoint時,也會更新第一個日誌文件的頭部checkpoint標記,所以嚴格來講也不算順序寫)。在覆蓋寫之前,總是要保證對應的髒頁已經刷到了磁盤。在非常大的負載下,Redo log可能產生的速度非常快,導致頻繁的刷髒操作,進而導致性能下降,通常在redo checkpoint的日誌超過文件總大小76%之後,InnoDB 認爲這可能是個不安全的點,會強制的preflush髒頁導致大量用戶線程停住
如果可預期會有這樣的場景:

建議調大redo log文件的大小。可以做一次乾淨的shutdown,然後修改Redo log配置重啓實例

Redo Log 如果要存儲數據先存儲數據的日誌 ,如果發生宕機導致數據丟失,就通過重做日誌進行數據恢復。重做日誌保證了數據的可靠性,InnoDB採用了Write Ahead Log(預寫日誌)策略,即當事務提交時先寫重做日誌,然後再擇時將髒頁寫入磁盤
在這裏插入圖片描述
InnoDB存儲引擎會首先將數據變更的重做日誌信息先放入重做日誌緩衝中,然後再按照一定頻率將其刷新到重做日誌文件。重做日誌緩衝一般不需要設置得很大,因爲一般情況每一秒鐘都會講重做日誌緩衝刷新到日誌文件中。可通過配置參數innodb_log_buffer_size控制,默認爲8MB

Redo 寫盤操作

我們所熟悉的參數innodb_flush_log_at_trx_commit作用於事務提交時,這也是最常見的場景:

  • 當設置該值爲1時,每次事務提交都要做一次fsync,這是最安全的配置,即使宕機也不會丟失事務
  • 當設置爲2時,則在事務提交時只做write操作,只保證寫到系統的page cache,因此實例crash不會丟失事務,但宕機則可能丟失事務
  • 當設置爲0時,事務提交不會觸發redo寫操作,而是留給後臺線程每秒一次的刷盤操作,因此實例crash將最多丟失1秒鐘內的事務

InnoDB的寫入機制大致入下圖所示。
在這裏插入圖片描述
顯然對性能的影響是隨着持久化程度的增加而增加的。通常我們建議在日常場景將該值設置爲1,但在系統高峯期臨時修改成2以應對大負載。
由於各個事務可以交叉的將事務日誌拷貝到log buffer中,因而一次事務提交觸發的redo到文件可能隱式的幫別的線程“順便”也寫了redo log,從而達到group commit的效果。

Redo checkpoint

check point目的是爲了定期data page buffer內容轉儲到data file。在轉儲時,會記錄check point發生的”時刻“。在故障恢復時候,只需要redo/undo最近的一次checkpoint之後的操作

InnoDB的redo log採用覆蓋循環寫的方式,而不是擁有無限的redo空間;即使擁有理論上極大的redo log空間,爲了從崩潰中快速恢復,及時做checkpoint也是非常有必要的

在innodb中,數據刷盤的規則只有一個:checkpoint。innodb存儲引擎中checkpoint分爲兩種:

  • sharp checkpoint:在重用redo log文件(例如切換日誌文件)的時候,將所有已記錄到redo log中對應的髒數據刷到磁盤。
  • fuzzy checkpoint一次只刷一小部分的日誌到磁盤,而非將所有髒日誌刷盤。
    有以下幾種情況會觸發該檢查點:
    • master thread checkpoint:由master線程控制,每秒或每10秒刷入一定比例的髒頁到磁盤。
    • flush_lru_list checkpoint:從MySQL5.6開始可通過 innodb_page_cleaners 變量指定專門負責髒頁刷盤的page cleaner線程的個數,該線程的目的是爲了保證lru列表有可用的空閒頁
    • async/sync flush checkpoint同步刷盤還是異步刷盤。例如還有非常多的髒頁沒刷到磁盤(非常多是多少,有比例控制),這時候會選擇同步刷到磁盤,但這很少出現;如果髒頁不是很多,可以選擇異步刷到磁盤,如果髒頁很少,可以暫時不刷髒頁到磁盤
    • dirty page too much checkpoint髒頁太多強制觸發檢查點,目的是爲了保證緩存有足夠的空閒空間。too much的比例由變量 innodb_max_dirty_pages_pct 控制,MySQL 5.6默認的值爲75,即當髒頁佔緩衝池的百分之75後,就強制刷一部分髒頁到磁盤。
      由於刷髒頁需要一定的時間來完成,所以記錄檢查點的位置是在每次刷盤結束之後纔在redo log中標記的。

InnoDB的master線程大約每隔10秒會做一次redo checkpoint,但不會去preflush髒頁來推進checkpoint點。

通常普通的低壓力負載下,page cleaner線程的刷髒速度足以保證可作爲檢查點的lsn被及時的推進。但如果系統負載很高時,redo log推進速度過快,而page cleaner來不及刷髒,這時候就會出現用戶線程陷入同步刷髒並做checkpoint的境地,這種策略的目的是爲了保證redo log能夠安全的寫入文件而不會覆蓋最近的檢查點。

參考:https://www.cnblogs.com/f-ck-need-u/archive/2018/05/08/9010872.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章