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表示是否加密