MySQL日誌之重作日誌redo

1.1 爲何須要redo

  數據庫爲了取得更好的讀寫性能,會將數據緩存在內存中,對磁盤數據的修改也會落後於內存,這時若是進程或機器崩潰,會致使內存數據丟失,爲了保證數據庫自己的一致性和持久性,InnoDB引入了redo log。修改數據頁以前須要先將修改的內容記錄到redo log中,並保證redo log早於對應的數據頁落盤,也就是常說的預寫式日誌(WAL)。當故障發生致使內存數據丟失後,InnoDB會在重啓時,經過重放REDO,將Page恢復到崩潰前的狀態。數據庫

1.2 redo log 結構

  redo log是物理日誌,記錄的是數據頁的物理修改,用來恢復提交後的物理數據頁。
  redo log包括兩部分:
緩存

  • 內存中的redo log buffer(內存數據,會丟失);
  • 磁盤上的redo log file(磁盤數據,持久化);

日誌塊
  innodb存儲引擎中,redo log以塊爲單位進行存儲的,每一個塊佔512字節,稱爲redo log block。因此無論是log buffer中仍是os buffer中以及redo log file中,都是這樣以512字節的塊存儲的,一個頁內能夠存放很是多的log block。
  每一個redo log block由3部分組成:日誌塊頭、日誌塊尾和日誌主體。其中日誌塊頭佔用12字節,日誌塊尾佔用8字節,因此每一個redo log block的日誌主體部分只有512-12-8=492字節。
日誌主體包含如下內容:


app

  • redo_log_type:佔用1個字節,表示redo log的日誌類型。
  • space:表示表空間的ID,採用壓縮的方式後,佔用的空間可能小於4字節。
  • page_no:表示頁的偏移量,一樣是壓縮過的。
  • redo_log_body表示每一個重作日誌的數據部分,恢復時會調用相應的函數進行解析。
    在這裏插入圖片描述

1.3 刷盤規則

  內存中未刷到磁盤的數據稱爲髒數據。log buffer中未刷到磁盤的日誌稱爲髒日誌。因爲數據和日誌都以頁的形式存在,因此髒頁分爲髒數據和髒日誌。
redo 髒日誌刷盤
異步

  • 按照innodb_flush_log_at_trx_commit設置刷盤async

  • 發出commit動做時。已經說明過,commit發出後是否刷日誌由變量 innodb_flush_log_at_trx_commit 控制。函數

  • 每秒刷一次。這個刷日誌的頻率由變量 innodb_flush_log_at_timeout 值決定,默認是1秒。要注意,這個刷日誌頻率和commit動做無關。性能

  • 當log buffer中已經使用的內存超過一半時。加密

  • 當有checkpoint時,checkpoint在必定程度上表明瞭刷到磁盤時日誌所處的LSN位置。spa

髒數據頁刷盤
  在innodb中,數據刷盤依賴於checkpoint。可是觸發checkpoint的狀況卻有幾種。checkpoint觸發後,會將buffer中髒數據頁和髒日誌頁都刷到磁盤。
線程

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後,就強制刷一部分髒頁到磁盤。

  MySQL中止時是否將髒數據和髒日誌刷入磁盤,由變量innodb_fast_shutdown={ 0|1|2 }控制,默認值爲1,即中止時只作一部分purge,忽略大多數flush操做(但至少會刷日誌),在下次啓動的時候再flush剩餘的內容,實現fast shutdown。

1.4 LSN

  LSN稱爲日誌的邏輯序列號(log sequence number),在innodb存儲引擎中,lsn佔用8個字節。LSN的值會隨着日誌的寫入而逐漸增大。LSN不只存在於redo log中,還存在於數據頁中,在每一個數據頁的頭部,有一個fil_page_lsn記錄了當前頁最終的LSN值是多少。經過數據頁中的LSN值和redo log中的LSN值比較,若是頁中的LSN值小於redo log中LSN值,則表示數據丟失了一部分,這時候能夠經過redo log的記錄來恢復到redo log中記錄的LSN值時的狀態。

show engine innodb status\G

---
LOG
---
#當前的log buffer中的lsn
Log sequence number          498732361
#Link_buf初始化的lsn
Log buffer assigned up to    498732361
#Link_buf完成的lsn
Log buffer completed up to   498732361
#到了這個lsn 爲止, 以前的log buffer 裏面都不會有空洞
Log written up to            498732361
刷到redo log file on disk中的lsn
Log flushed up to            498732361
#redo log 對應的dirty page 已經添加到buffer pool 的flush list
Added dirty pages up to      498732361
#已經刷到磁盤數據頁上的LSN
Pages flushed up to          498732361
#上一次檢查點所在位置的LSN
Last checkpoint at           498732361
1092 log i/o's done, 0.00 log i/o's/second

Log sequence number>=Log buffer assigned up to>=Log buffer completed up to>=Log written up to>=Log flushed up to>=Added dirty pages up to>=Pages flushed up to>=Last checkpoint at

1.5 相關變量

  • innodb_flush_log_at_trx_commit指定什麼時候將事務日誌刷到磁盤,默認爲1。
    • 0表示每秒將"log buffer"同步到"os buffer"且從"os buffer"刷到磁盤日誌文件中。
    • 1表示每事務提交都將"log buffer"同步到"os buffer"且從"os buffer"刷到磁盤日誌文件中。
    • 2表示每事務提交都將"log buffer"同步到"os buffer"但每秒才從"os buffer"刷到磁盤日誌文件中。
  • innodb_flush_log_at_timeout 定義了每第二天志刷新的時間,與innodb_flush_log_at_trx_commit 配合使用
  • innodb_log_buffer_size表示log buffer的大小
  • innodb_log_file_size事務日誌的大小
  • innodb_log_checksums表示在寫入redo log到文件以前,redo log的每個block都須要加上checksum校驗位,以防止apply損壞redo log
  • innodb_log_files_group事務日誌組中的事務日誌文件個數
  • innodb_log_group_home_dir事務日誌組路徑,當前目錄表示數據目錄
  • innodb_redo_log_archive_dirs是redo歸檔目錄
  • innodb_redo_log_encrypt表示是否加密
相關文章
相關標籤/搜索