從物理文件理解InnoDB Redo Log-愛可生

導讀

作為MySQL DBA都應該知道,Redo Log是可被覆蓋的,是ACID中的D的最重要的構成部分,也就是關係型數據庫中的WAL中的L。

Redo Log記錄的是redo,那麼redo是什麼呢?通俗來講,redo記錄的是對應的記錄改變的物理操作。說實話,過去的很長一段時間內,我對redo的認識也僅限於此,並沒有好好深入理解redo記錄的到底是什麼。這次從redo的物理結構上深入理解下redo到底是什麼。

Redo Log邏輯&物理結構

從物理文件理解InnoDB Redo Log-愛可生

從邏輯上來講,redo log記錄是連續遞增的,但是對應到物理文件就不一樣了,考慮到磁盤空間,redo log被設計成了多個可循環寫入的文件。InnoDB要求Redo Log,文件至少有2個,初始文件為 ib_logfile0和 ib_logfile1, ib_logfile0寫完以後寫 ib_logfile1,等到 ib_logfile1也寫完了,從頭又開始寫 ib_logfile0,這樣就形成了一個環形寫入的結構。但是覆蓋寫入的前提是要確定哪個位置點是可以覆蓋寫的,哪些位置是不能覆蓋寫的,這個就是check point的工作了,關於checkpoint可以關注我上一篇文章《MySQL Checkpoint》。

Log File物理結構

從物理文件理解InnoDB Redo Log-愛可生

從物理文件理解InnoDB Redo Log-愛可生

從 ib_logfile0和 ib_logfile1這兩個文件的物理結構可以看出,在Log Header部分還是有些許差異的, ib_logfile0會多一些額外的信息,主要是checkpoint信息。

並且每個Block的單位是512字節,對應到磁盤每個扇區也是512字節,因此redo log寫磁盤是原子寫,保證能夠寫成功,而不像index page一樣需要double write來保證安全寫入。

我們依次從上到下來看每個Block的結構

Log File Header Block

從物理文件理解InnoDB Redo Log-愛可生

  • Log Goup ID,可能會配置多個redo組,每個組對應一個id,當前都是0,佔用4字節
  • Start LSN,這個redo log文件開始日誌的lsn,佔用8字節
  • Log File Number,總是為0,佔用4字節
  • Created By,備份程序所佔用的字節數,佔用32字節

另外在ib_logfile0中會有兩個checkpoint block,分別是 LOG_CHECKPOINT_1/ LOG_CHECKPOINT_2,兩個記錄InnoDB Checkpoint信息的字段,分別從文件頭的第二個和第四個block開始記錄,並且只在每組log的第一個文件中存在,組內其他文件雖然沒有checkpoint相關信息,但是也會預留相應的空間出來。這裡為什麼有兩個checkpoint的呢?原因是設計為交替寫入,避免因為介質失敗而導致無法找到可用的checkpoint的情況。

Log blocks

從物理文件理解InnoDB Redo Log-愛可生

log block結構分為日誌頭段、日誌記錄、日誌尾部

  • Block Header,佔用12字節
  • Data部分
  • Block tailer,佔用4字節

Block Header

這個部分是每個Block的頭部,主要記錄的塊的信息

  • Block Number,表示這是第幾個block,佔用4字節,是通過LSN計算得來的,佔用4字節
  • Block data len,表示該block中有多少字節已經被使用了,佔用2字節
  • First Rec offet,表示該block中作為第一個新的mtr開始的偏移量,佔用2字節
  • Checkpoint number,表示該log block最後被寫入時的檢查點的值,佔用4字節

Data部分

這部分才開始真正記錄我們理解的redo log,實際真正可用字節數為512-12-4=496字節,用戶的redo是以一條一條的記錄存放在這個block的data部分,並且一條redo記錄可能會佔用多個block

Block tailfer

tailer部分就比較簡單了,只是記錄一個checksum值,用於正確性校驗,佔用4字節

Log Record

從物理文件理解InnoDB Redo Log-愛可生

從物理文件理解InnoDB Redo Log-愛可生

沒錯,redo記錄就是這個結構,分為頭部、body部分

通用header

  • redo_log_type,重做日誌的類型
  • space ID,表空間ID
  • Page Numer,用於定位哪個page

redo包括幾種類型,M_LOG_WRITE_1BYTE、M_LOG_WRITE_2BYTE、M_LOG_WRITE_4BYTE和M_LOG_WRITE_STRING等,其頭部格式如下所示

從物理文件理解InnoDB Redo Log-愛可生

從物理文件理解InnoDB Redo Log-愛可生


一條完整的INSERT redo record

從物理文件理解InnoDB Redo Log-愛可生

關於LSN

LSN幾乎是redo中最重要的概念之一了,LSN表示redo的寫入量,標識了checkpoint的位置,標識了page的版本。LSN不僅存在與redo log中,還存在於每個page中。在每個page的頭部,有一個 FIL_PAGE_LSN,記錄了page的LSN,表示該頁最後刷新時的LSN大小。redo中記錄的是每個page的日誌,因此page中的LSN用來判斷是否需要進行恢復操作,這對於MySQL的崩潰恢復及其重要。

關於redo刷盤機制

大概有以下幾種情況會觸發redo log刷盤

  1. log buffer空間用完了,這就會將已經產生的log buffer中的日誌刷到磁盤中,這是最普遍的一種方式;
  2. master線程在後臺每秒鐘刷一次,將當前log buffer中的日誌刷到磁盤中;
  3. 每次執行DML操作時,都會主動檢查日誌空間是否足夠,如果使用空間的量已經超過了一個預設的經驗值,就會主動刷日誌,以保證在後面真正執行時,不會再執行過程中被動的刷盤,但這裡只會是寫文件(寫入OS緩衝中)不會刷盤
  4. 在做checkpoint的時候,要保證所有要刷的頁面中LSN值最小的日誌已經刷入到磁盤,不然,如果此時數據庫宕機,日誌不存在,但數據頁面已經被修改,從而導致數據不一致,就違背了寫日誌的原則;
  5. 提交邏輯事務時,會因為參數 innodb_flush_log_at_trx_commit值的不同,產生不同的行為。如果設置0,則在事務提交時,不會去刷日誌緩衝區,等待master thread以固定頻率去刷盤,這種設置是最危險的 如果設置2,則在事務提交時會將日誌寫入到文件中,但不會去刷盤,只要操作系統不掛,即使數據庫掛了,數據還是不會丟失 如果設置1,則在事務提交的時候將日誌寫入文件同時fsync,保證redo log落盤,生產環境主庫強烈建議設置為1

幾個建議:

  1. innodb_flush_log_at_trx_commit設置為1
  2. redo log建議設置2G,組數建議為3組以上,避免因為redo log切換導致性能抖動
  3. redo log buffer建議設置32M以上(根據實際情況至少能夠緩存1秒的redo)


分享到:


相關文章: