基於MySQL5.7版本,5.7版本在恢復過程做了優化,本文描述不考慮之前版本。
1 初始化崩潰恢復
數據庫關閉只有2種情況,正常關閉,非正常關閉(包括數據庫實例crash及服務器crash)。
正常關閉情況,所有buffer pool里邊的臟頁都會都會刷新一遍到磁盤,同時記錄最新LSN到ibdata文件的第一個page中。而非正常關閉來不及做這些操作,也就是沒及時把臟數據flush到磁盤,也沒有記錄最新LSN到ibdata file。
當我們重啟數據庫實例的時候,數據庫做2個階段性操作:redo log處理,undo log及binlog 處理。
1.1 redo log處理
- 打開系統表空間ibdata,讀取第一個page中的LSN,若第一個頁損壞,則依次往后面的page讀,知道有個完整的page能夠提供LSN,這個LSN當作上次shutdown時的checkpoint點,后續恢復,從這個LSN點開始恢復
- 進入redo log文件,讀取第一個redo log文件頭的checkpoint LSN, 並根據該LSN定位到redo日志文件中對應的位置,從該checkpoint點開始掃描,進行3次redo log文件掃描:
-
- 第一次,找 MLOG_CHECKPOINT日志
-
-
- 如果是正常關閉,這個日志是不做記錄的,也就是掃描的過程中不回找到對應的MLOG_CHECKPOINT日志,不會進行接下來的兩次掃描,因為屬於正常關閉數據庫服務,不需要考慮奔潰恢復情況;
-
-
-
- 如果是非正常關閉,則會查找到 MLOG_CHECKPOINT (如果是多個,則說明redo文件已損壞,恢復報錯),獲取MLOG_FILE_NAME中指定后續需要恢復的ibd文件;
-
-
- 第二次,從redo log讀到的LSN,找到checkpoint點開始重復掃描存儲日志對象
-
-
- 根據MLOG_CHECKPOINT日志,讀取對應LSN之后的日志解析到hash表中,如果剩下的日志解析結束后還沒有填滿hash表格,則不需要進行第三次掃描;
-
-
-
- 進行到這里,則說明數據庫是非正常關閉,會在errorlog中提示:Database was not shutdown normally!詳見下圖。
-
-
- 第三次,若第二次掃描hash表空間不足,則發起第三次掃描,清空hash表空間,重新從新的checkpoint點開始掃描
-
-
- 如果第二次掃掃描就把hash表填滿,那么會先把hash表里邊的記錄重做到buffer pool中的數據頁,然后再來加載redo log 記錄到被清空的hash表中,hash表滿后立即執行恢復操作,知道所有需要redo 的redo log 被應用結束。
-
恢復的過程中,注意兩個點:打開ibd文件形式,讀取數據庫到buffer pool的改進。
根據hash表中的相應信息讀取數據頁, 讀數據頁的時候,5.7之前版本采用把所有表空間都打開,所有表格僅執行ReadOnly,5.7版本做了優化,新增了 MLOG_FILE_NAME 記錄在checkpoint之后,所有被修改過的信息,根據這些信息,在恢復過程中,只需要打開相應的ibd文件即可,不涉及恢復的表格支持正常DML跟DDL操作,涉及恢復的表格則僅執行ReadOnly功能。
當把數據頁讀取到buffer pool中,以往版本是只讀取對應的 單個頁面,而現在的是直接讀取與該頁面相鄰的32個data page 也一起加載的buffer pool,因為一個數據頁的修改,可能周圍的頁面也被修改,一次性讀取,可以避免后面根據hash表中再重新讀取其相鄰的頁面。1.2 undo log及binlog 處理
上一階段中,把redo log中的操作都apply到數據頁中,但是對於prepare狀態的事務卻還沒有進行回滾處理,這個階段則是針對prepare狀態的事務進行處理,需要使用到binlog和undo log。
- 根據最后一個binlog文件,為啥不是所有binlog文件呢?因為每一個binlog文件切換的時候,都會確保當前binlog文件的所有操作已落盤,所以只需要考慮最后一個binlog文件。跟進最后一個binlog文件,獲取所有可能沒有提交事務的xid列表;
- 根據undo log中的 insert_undo_list,upddate_undo_list事務鏈,構建undo_list,在根據undo_list構建未提交事務鏈表;
- 從未提交事務鏈表中,提取出xid,凡是存在於xid列表中的,則需要提交,不存在的,則回滾。
整個恢復過程,可以參考下來自 www.sysdb.cn 網站作者 boyce 畫的說明圖,圖片版權屬於該作者,本處僅為引用分享給大家,作圖很詳細,一言不合開源碼分析!遺憾的是,作者只寫了2篇博文就停止更新了,心疼默哀十分鍾.....
2 innodb關閉恢復涉及參數
2.1 關閉參數:innodb_fast_shutdown
數據庫關閉的時候,innodb需要完成所有full purge何insert buffer操作,這需要一些時間,甚至幾個小時完成
- 0
- 關閉時,需要完成所有full purge,insert buffer, flush dirty pages操作
- 做 innodb plugin升級時,會設置為0,再正常關閉數據庫。
- 1
- 默認值,表示不需要完成full purge和insert buffer操作,但是緩沖池的臟數據需要刷新到磁盤
- 2
- 既不完成full purge和insert buffer操作,也不把緩沖池的臟數據刷新到磁盤,而是將日志寫入日志文件,這樣不回有數據丟失,但是下次mysql啟動的時候,需要根據日志文件執行恢復操作
2.2 恢復參數:innodb_force_recovery
這里注意,數字越小,則忽略檢查的內容越少,每個大的數字都包含了前面小數字忽略檢查的內容。當參數設置大於0后,可以對表格進行DML操作,但是DDL操作時不允許的。
當innodb_force_recovery 值為1-3時,僅允許SELECT TABLE ,DROP or CREATE tables;innodb_force_recovery 值為>=4時,5.7.17之前版本支持DROP TABLE,5.7.18后版本不支持。
參數說明如下圖:

3 測試情況
3.1 默認配置測試:innodb_fast_shutdown=1,innodb_force_recovery=0
3.1.1 操作過程
1 #1 tailf error.log查看mysql錯誤日志,動態滾動查看 2 mysql> show global variables like 'log_error'; 3 tailf /data/mysql/mysql3310/data/error.log 4 5 #2 測試庫中開啟事務,insert 10w行記錄,不提交事務 6 mysql> begin;insert into orders select * from orders.orders limit 100000; 7 Query OK, 0 rows affected (0.00 sec) 8 9 Query OK, 100000 rows affected (37.55 sec) 10 Records: 100000 Duplicates: 0 Warnings: 0 11 12 #3 查找mysql進程號,殺進程 13 [root@localhost opt]# ps axu | grep mysql 14 [root@localhost opt]# kill -9 mysql的進程號 15 16 #4 啟動mysql服務 17 mysqld --defaults-file=/data/mysql/mysql3310/mysql3310.cnf & 18 19 #5 到tailf error.log窗口查看錯誤
3.1.2 error log解析

1 2017-03-16T16:28:13.812074Z 0 [Note] mysqld (mysqld 5.7.14-log) starting as process 28091 ... 2 2017-03-16T16:28:14.250956Z 0 [Note] InnoDB: PUNCH HOLE support not available 3 2017-03-16T16:28:14.251212Z 0 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins 4 2017-03-16T16:28:14.251311Z 0 [Note] InnoDB: Uses event mutexes 5 2017-03-16T16:28:14.251359Z 0 [Note] InnoDB: GCC builtin __sync_synchronize() is used for memory barrier 6 2017-03-16T16:28:14.251401Z 0 [Note] InnoDB: Compressed tables use zlib 1.2.3 7 2017-03-16T16:28:14.251311Z 0 [Note] InnoDB: Uses event mutexes 8 2017-03-16T16:28:14.251359Z 0 [Note] InnoDB: GCC builtin __sync_synchronize() is used for memory barrier 9 2017-03-16T16:28:14.251401Z 0 [Note] InnoDB: Compressed tables use zlib 1.2.3 10 2017-03-16T16:28:14.251440Z 0 [Note] InnoDB: Using Linux native AIO 11 2017-03-16T16:28:14.252570Z 0 [Note] InnoDB: Number of pools: 1 12 2017-03-16T16:28:14.253079Z 0 [Note] InnoDB: Not using CPU crc32 instructions 13 2017-03-16T16:28:14.258163Z 0 [Note] InnoDB: Initializing buffer pool, total size = 9G, instances = 8, chunk size = 128M 14 2017-03-16T16:28:16.101862Z 0 [Note] InnoDB: Completed initialization of buffer pool 15 2017-03-16T16:28:16.406890Z 0 [Note] InnoDB: If the mysqld execution user is authorized, page cleaner thread priority can be changed. See the man page of setpriority(). 16 2017-03-16T16:28:16.447145Z 0 [Note] InnoDB: Highest supported file format is Barracuda. 17 2017-03-16T16:28:16.572276Z 0 [Note] InnoDB: Log scan progressed past the checkpoint lsn 898634772645 18 2017-03-16T16:28:16.572418Z 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 898634772654 19 2017-03-16T16:28:16.693771Z 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 898634772654 20 2017-03-16T16:28:16.693880Z 0 [Note] InnoDB: Database was not shutdown normally! 21 2017-03-16T16:28:16.693913Z 0 [Note] InnoDB: Starting crash recovery. 22 2017-03-16T16:28:17.360953Z 0 [Note] InnoDB: 1 transaction(s) which must be rolled back or cleaned up in total 100000 row operations to undo 23 2017-03-16T16:28:17.361122Z 0 [Note] InnoDB: Trx id counter is 5716480 24 2017-03-16T16:28:17.625441Z 0 [Note] InnoDB: Last MySQL binlog file position 0 37774, file name bin_log.000016 25 2017-03-16T16:28:17.787684Z 0 [Note] InnoDB: Starting in background the rollback of uncommitted transactions 26 2017-03-16T16:28:17.788022Z 0 [Note] InnoDB: Rolling back trx with id 5715975, 100000 rows to undo 27 28 InnoDB: Progress in percents: 12017-03-16T16:28:17.788272Z 0 [Note] InnoDB: Removed temporary tablespace data file: "ibtmp1" 29 2017-03-16T16:28:17.788603Z 0 [Note] InnoDB: Creating shared tablespace for temporary tables 30 2017-03-16T16:28:17.788603Z 0 [Note] InnoDB: Creating shared tablespace for temporary tables 31 2017-03-16T16:28:17.788937Z 0 [Note] InnoDB: Setting file './ibtmp1' size to 12 MB. Physically writing the file full; Please wait ... 32 2017-03-16T16:28:17.831078Z 0 [Note] InnoDB: File './ibtmp1' size is now 12 MB. 33 2017-03-16T16:28:17.834673Z 0 [Note] InnoDB: 96 redo rollback segment(s) found. 96 redo rollback segment(s) are active. 34 2017-03-16T16:28:17.834822Z 0 [Note] InnoDB: 32 non-redo rollback segment(s) are active. 35 2017-03-16T16:28:17.838323Z 0 [Note] InnoDB: Waiting for purge to start 36 2017-03-16T16:28:18.015792Z 0 [Note] InnoDB: 5.7.14 started; log sequence number 898634772654 37 2017-03-16T16:28:18.018091Z 0 [Note] InnoDB: Loading buffer pool(s) from /data/mysql/mysql3310/data/ib_buffer_pool 38 2017-03-16T16:28:18.018464Z 0 [Note] Plugin 'FEDERATED' is disabled. 39 2017-03-16T16:28:18.119301Z 0 [Note] Recovering after a crash using /data/mysql/mysql3310/logs/bin_log 40 2017-03-16T16:28:18.119442Z 0 [Note] Starting crash recovery... 41 2017-03-16T16:28:18.119442Z 0 [Note] Starting crash recovery... 42 2017-03-16T16:28:18.119624Z 0 [Note] Crash recovery finished. 43 2017-03-16T16:28:18.203723Z 0 [Warning] Failed to set up SSL because of the following SSL library error: SSL context is not usable without certificate and private key 44 2017-03-16T16:28:18.203835Z 0 [Note] Server hostname (bind-address): '*'; port: 3310 45 2017-03-16T16:28:18.204188Z 0 [Note] IPv6 is available. 46 2017-03-16T16:28:18.204339Z 0 [Note] - '::' resolves to '::'; 47 2017-03-16T16:28:18.204667Z 0 [Note] Server socket created on IP: '::'. 48 2017-03-16T16:28:18.377789Z 0 [Warning] 'user' entry 'mysql.sys@localhost' ignored in --skip-name-resolve mode. 49 2017-03-16T16:28:18.378054Z 0 [Warning] 'db' entry 'sys mysql.sys@localhost' ignored in --skip-name-resolve mode. 50 2017-03-16T16:28:18.378170Z 0 [Warning] 'proxies_priv' entry '@ root@localhost' ignored in --skip-name-resolve mode. 51 2017-03-16T16:28:18.392680Z 0 [Warning] 'tables_priv' entry 'sys_config mysql.sys@localhost' ignored in --skip-name-resolve mode. 52 2017-03-16T16:28:18.771122Z 0 [Note] Event Scheduler: Loaded 0 events 53 2017-03-16T16:28:18.772035Z 0 [Note] mysqld: ready for connections. 54 Version: '5.7.14-log' socket: '/tmp/mysql3310.sock' port: 3310 MySQL Community Server (GPL) 55 2017-03-16T16:28:21.404135Z 0 [Note] InnoDB: Buffer pool(s) load completed at 170317 0:28:21 56 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 1002017-03-16T16:29:24.353056Z 0 [Note] InnoDB: Rollback of trx with id 5715975 completed 57 2017-03-16T16:29:24.353267Z 0 [Note] InnoDB: Rollback of non-prepared transactions completed
3.2 innodb_fast_shutdown=1,innodb_force_recovery=3
3.2.1 操作過程
1 #1 tailf error.log查看mysql錯誤日志,動態滾動查看 2 mysql> show global variables like 'log_error'; 3 tailf /data/mysql/mysql3310/data/error.log 4 5 #2 測試庫中開啟事務,insert 10w行記錄,不提交事務 6 mysql> begin;insert into orders select * from orders.orders limit 100000; 7 Query OK, 0 rows affected (0.00 sec) 8 9 Query OK, 100000 rows affected (37.55 sec) 10 Records: 100000 Duplicates: 0 Warnings: 0 11 12 #3 查找mysql進程號,殺進程 13 [root@localhost opt]# ps axu | grep mysql 14 [root@localhost opt]# kill -9 mysql的進程號 15 16 #4 在cnf文件中指定innodb_force_recovery=3,啟動服務,檢查是否修改成功 17 [root@localhost ~]# vim /data/mysql/mysql3310.cnf 18 #添加innodb_force_recovery參數設置 19 [mysqld] 20 innodb_force_recovery=3 21 22 #5 啟動mysql服務 23 [root@localhost ~]# mysqld --defaults-file=/data/mysql/mysql3310.cnf & 24 25 #6 到tailf error.log窗口查看錯誤 26 #發現沒有進行undo操作,同時全庫僅支持select drop create,不支持其他所有操作
3.2.2 error log解析

1 2017-03-17T15:12:14.317391Z 0 [Note] mysqld (mysqld 5.7.14-log) starting as process 32094 ... 2 2017-03-17T15:12:14.430101Z 0 [Note] InnoDB: PUNCH HOLE support not available 3 2017-03-17T15:12:14.430586Z 0 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins 4 2017-03-17T15:12:14.430732Z 0 [Note] InnoDB: Uses event mutexes 5 2017-03-17T15:12:14.430874Z 0 [Note] InnoDB: GCC builtin __sync_synchronize() is used for memory barrier 6 2017-03-17T15:12:14.430993Z 0 [Note] InnoDB: Compressed tables use zlib 1.2.3 7 2017-03-17T15:12:14.431084Z 0 [Note] InnoDB: Using Linux native AIO 8 2017-03-17T15:12:14.433127Z 0 [Note] InnoDB: Number of pools: 1 9 2017-03-17T15:12:14.434016Z 0 [Note] InnoDB: Not using CPU crc32 instructions 10 2017-03-17T15:12:14.443970Z 0 [Note] InnoDB: Initializing buffer pool, total size = 9G, instances = 8, chunk size = 128M 11 2017-03-17T15:12:16.158820Z 0 [Note] InnoDB: Completed initialization of buffer pool 12 2017-03-17T15:12:16.380118Z 0 [Note] InnoDB: If the mysqld execution user is authorized, page cleaner thread priority can be changed. See the man page of setpriority(). 13 2017-03-17T15:12:16.409819Z 0 [Note] InnoDB: Highest supported file format is Barracuda. 14 2017-03-17T15:12:16.478403Z 0 [Note] InnoDB: Log scan progressed past the checkpoint lsn 898935661420 15 2017-03-17T15:12:16.478579Z 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 898935661429 16 2017-03-17T15:12:16.532923Z 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 898935661429 17 2017-03-17T15:12:16.533063Z 0 [Note] InnoDB: Database was not shutdown normally! 18 2017-03-17T15:12:16.533105Z 0 [Note] InnoDB: Starting crash recovery. 19 2017-03-17T15:12:17.052734Z 0 [Note] InnoDB: 1 transaction(s) which must be rolled back or cleaned up in total 100000 row operations to undo 20 2017-03-17T15:12:17.053009Z 0 [Note] InnoDB: Trx id counter is 5718016 21 2017-03-17T15:12:17.321987Z 0 [Note] InnoDB: Last MySQL binlog file position 0 37774, file name bin_log.000016 22 2017-03-17T15:12:17.460435Z 0 [Note] InnoDB: Removed temporary tablespace data file: "ibtmp1" 23 2017-03-17T15:12:17.460673Z 0 [Note] InnoDB: Creating shared tablespace for temporary tables 24 2017-03-17T15:12:17.461075Z 0 [Note] InnoDB: Setting file './ibtmp1' size to 12 MB. Physically writing the file full; Please wait ... 25 2017-03-17T15:12:17.512923Z 0 [Note] InnoDB: File './ibtmp1' size is now 12 MB. 26 2017-03-17T15:12:17.516337Z 0 [Note] InnoDB: 96 redo rollback segment(s) found. 96 redo rollback segment(s) are active. 27 2017-03-17T15:12:17.516617Z 0 [Note] InnoDB: 32 non-redo rollback segment(s) are active. 28 2017-03-17T15:12:17.518732Z 0 [Note] InnoDB: 5.7.14 started; log sequence number 898935661429 29 2017-03-17T15:12:17.518789Z 0 [Note] InnoDB: !!! innodb_force_recovery is set to 3 !!! 30 2017-03-17T15:12:17.519305Z 0 [Note] InnoDB: Loading buffer pool(s) from /data/mysql/mysql3310/data/ib_buffer_pool 31 2017-03-17T15:12:17.521217Z 0 [Note] Plugin 'FEDERATED' is disabled. 32 2017-03-17T15:12:17.694697Z 0 [Note] Recovering after a crash using /data/mysql/mysql3310/logs/bin_log 33 2017-03-17T15:12:17.694882Z 0 [Note] Starting crash recovery... 34 2017-03-17T15:12:17.695070Z 0 [Note] Crash recovery finished. 35 2017-03-17T15:12:18.197454Z 0 [Warning] Failed to set up SSL because of the following SSL library error: SSL context is not usable without certificate and private key 36 2017-03-17T15:12:18.197584Z 0 [Note] Server hostname (bind-address): '*'; port: 3310 37 2017-03-17T15:12:18.197804Z 0 [Note] IPv6 is available. 38 2017-03-17T15:12:18.197910Z 0 [Note] - '::' resolves to '::'; 39 2017-03-17T15:12:18.197981Z 0 [Note] Server socket created on IP: '::'. 40 2017-03-17T15:12:18.391615Z 0 [Note] InnoDB: Buffer pool(s) load completed at 170317 23:12:18 41 2017-03-17T15:12:18.414950Z 0 [Warning] 'user' entry 'mysql.sys@localhost' ignored in --skip-name-resolve mode. 42 2017-03-17T15:12:18.415223Z 0 [Warning] 'db' entry 'sys mysql.sys@localhost' ignored in --skip-name-resolve mode. 43 2017-03-17T15:12:18.415340Z 0 [Warning] 'proxies_priv' entry '@ root@localhost' ignored in --skip-name-resolve mode. 44 2017-03-17T15:12:18.446935Z 0 [Warning] 'tables_priv' entry 'sys_config mysql.sys@localhost' ignored in --skip-name-resolve mode. 45 2017-03-17T15:12:18.520569Z 0 [Note] Event Scheduler: Loaded 0 events 46 2017-03-17T15:12:18.521680Z 0 [Note] mysqld: ready for connections. 47 Version: '5.7.14-log' socket: '/tmp/mysql3310.sock' port: 3310 MySQL Community Server (GPL) 48 2017-03-17T15:13:03.125686Z 2 [ERROR] InnoDB: innodb_force_recovery is on. We do not allow database modifications by the user. Shut down mysqld and edit my.cnf to set innodb_force_recovery=0