vc mysql init 崩潰_故障分析 | 崩潰恢復巨慢原因分析

作者:xuty

本文來源:原創投稿

*愛可生開源社區出品,原創內容未經授權不得隨意使用,轉載請聯系小編并注明來源。

一、現象

有個 MySQL 5.7 開發庫異常掛掉后,奔潰恢復一直處于如下位置,且持續了 2 小時左右才起來。非常疑惑這段時間 MySQL 到底做了什么事情?居然需要這么長時間。雖說這里虛擬機的 IOPS 并不是很高,但也絕對不需要這么久吧?而且從日志輸出來看,這塊應該也不是在做真正的數據恢復,那么也可以排除是大事務回滾導致的耗時長,那么原因到底是啥呢?

值得注意的是,這臺開發庫上面有將近 1500 個庫和上萬張表,難道MySQL 崩潰恢復時長和表的數量也存在一定關系嘛?

476197aedad1a84db6109402d76bcaff.png

二、分析棧幀

在 MySQL 崩潰恢復時,用pstack打了棧幀,再用pt-pmp工具分析棧幀后顯示如下:

pread64(libpthread.so.0),os_file_io(os0file.cc:5435),os_file_pread(os0file.cc:5612),os_file_read_page(os0file.cc:5612),os_file_read_no_error_handling_func(os0file.cc:6069),pfs_os_file_read_no_error_handling_func(os0file.ic:341),Datafile::read_first_page(os0file.ic:341),Datafile::validate_first_page(fsp0file.cc:551),Datafile::validate_to_dd(fsp0file.cc:404),fil_ibd_open(fil0fil.cc:3969),dict_check_sys_tables(dict0load.cc:1465),dict_check_tablespaces_and_store_max_id(dict0load.cc:1525),innobase_start_or_create_for_mysql(srv0start.cc:2329),innobase_init(ha_innodb.cc:4048),ha_initialize_handlerton(handler.cc:838),plugin_initialize(sql_plugin.cc:1197),plugin_init(sql_plugin.cc:1538),init_server_components(mysqld.cc:4033),mysqld_main(mysqld.cc:4673),__libc_start_main(libc.so.6),_start根據函數名字,感覺像是在遍歷校驗每個表空間文件的有效性?,難道 MySQL 崩潰恢復時會額外進行校驗操作?貌似和表數量扯上點關系了。

三、GDB 調試Server version: 5.7.26-log MySQL Community Server (GPL)

直接去分析源碼感覺有點找不到切入點,因為不知道正常啟動是不是也是這樣的函數調用。為了知道正常啟動與崩潰恢復的區別,先在本地的 MySQL 5.7.26 環境中用 GDB 調試 MySQL 啟動過程,看下正常啟動和崩潰恢復的函數調用有哪些區別,再針對性的去分析源碼比較好。

-- 將之前的棧幀弄成了樹狀,便于分析>innobase_init| >innobase_start_or_create_for_mysql| | >dict_check_tablespaces_and_store_max_id| | | >dict_check_sys_tables| | | | >fil_ibd_open| | | | | >Datafile::validate_to_dd| | | | | | >Datafile::validate_first_page| | | | | | | >Datafile::read_first_page| | | | | | | | >pfs_os_file_read_no_error_handling_func| | | | | | | | | >os_file_read_no_error_handling_func| | | | | | | | | | >os_file_read_page| | | | | | | | | | | >os_file_pread| | | | | | | | | | | | >os_file_io

正常啟動 GDB 調試結果:

從上到下,每次打一個斷點函數,發現到Datafile::validate_to_dd這個函數時,MySQL 正常啟動就不會執行,看樣子是fil_ibd_open函數中做了某些判斷。

崩潰恢復 GDB 調試結果:

一邊用 sysbench 壓,一邊直接 kill -9 進程就可以模擬崩潰恢復,同樣從上到下,依次打斷點函數,發現會走到Datafile::validate_to_dd這個函數中,Continue 后會一直斷點在這個函數上,說明外層包裝了一層循環會遍歷所有表,如果繼續增加斷點函數的話,發現絕大部分表會繼續走下去,直到os_file_io,而小部分表則不會繼續走下去。

四、源碼分析

4.1. fil_ibd_open

我們先去fil_ibd_open函數中看下,進入Datafile::validate_to_dd函數的判斷條件,發現主要和一個validate參數有關,如果為false則可以跳過檢測,為true則需要進入Datafile::validate_to_dd函數。

6efda04ba408aeac9bae7efef07d1ed9.png

4.2. innobase_start_or_create_for_mysql

然后我們需要看下validate參數的定義,分析崩潰恢復與正常啟動的區別。發現validate 參數最早是在innobase_start_or_create_for_mysql函數中定義的,并且其注釋已經解釋的非常詳細。1. 正常啟動:直接為每張表的創建 space object 即可,不需要打開 ibd 文件的 header page 進行表空間校驗。2. 崩潰恢復:為了數據字典的一致性,需要遍歷打開所有 ibd 文件的 header page 進行表空間校驗。

validate 這個參數表明當一個表空間被打開時,同時會去讀取其 ibd 文件的頭頁(header page)來驗證數據字典的一致性,而當數據庫包含許多 ibd 文件時,這個過程就會比較久,所以只在崩潰恢復且非強制恢復時執行表空間校驗操作!

83499c010be0e8bfc3bae8b91604a2ed.png

4.3. recv_needed_recovery & srv_force_recovery

接著我們來看下決定 validate 值的 2 個參數:recv_needed_recovery與srv_force_recovery,默認崩潰恢復時,recv_needed_recovery = 1 而 srv_force_recovery = 0 ,所以 validate = true,即需要進行表空間校驗。

bool validate = recv_needed_recovery && srv_force_recovery == 0;//跳過表空間校驗validate = false//執行表空間校驗validate = true先看下recv_needed_recovery參數,默認為 0。MySQL 在啟動時會比對checkpoint_lsn與flush_lsn。如果不相等,就會調用recv_init_crash_recovery方法將recv_needed_recovery置為。只有當 MySQL 正常關閉時,這 2 個 lsn 才會相等。另外一個小發現,MySQL 5.7 中服務起來后,什么操作都不做,checkpoint_lsn 永遠會落后 9,所以即使你什么都不做,直接 kill -9 進程,也算是崩潰重啟。

LOG---Log sequence number 2563079308Log flushed up to 2563079308Pages flushed up to 2563079308Last checkpoint at 2563079299

bb5d5dd8483a8e709043c9f90b882071.png

再來看下srv_force_recovery參數,默認值為 0,如果設置了 innodb_force_recovery ,那么 srv_force_recovery 的值就等于 innodb_force_recovery 的值,即只要配置了強制恢復,srv_force_recovery 就會大于 0。

4.4. dict_check_tablespaces_and_store_max_id

最后看下dict_check_tablespaces_and_store_max_id函數,根據注釋介紹,這個函數會檢查所有在數據字典中發現的表空間, 先檢查每個共享表空間,然后檢查每個獨立表空間。

在崩潰恢復中,部分表空間已經在處理 redolog 時被打開(對應之前 GDB 調試時部分表未繼續走下去),而其他沒有被打開的表空間,將會通過比較數據字典中的 space_id 與表空間文件是否一致的方式進行驗證(也就是之前所說的表空間校驗過程)。

fd972f10b183db7bf1f11d80036c512d.png

五、測試驗證

到這里,原理大概已經知道了,主要就是:MySQL 在崩潰恢復時,會遍歷打開所有 ibd 文件的 header page 驗證數據字典的準確性,如果 MySQL 中包含了大量表,這個校驗過程就會比較耗時。那么我們可以模擬下這個場景,進一步驗證,比如在測試庫中用 sysbench 建 50W 張空表,然后模擬非正常關閉,對比下崩潰恢復時長。

06b871b9044ea0ab4b7d56d1af4b1008.png

可以看到 MySQL 下崩潰恢復確實和表數量有關,表總數越大,崩潰恢復時間越長。另外磁盤 IOPS 也會影響崩潰恢復時間,像這里開發庫的 HDD IOPS 較低,因此面對大量的表空間,校驗速度就非常緩慢。另外一個發現,MySQL 8 下正常啟用時居然也會進行表空間校驗,而故障恢復時則會額外再進行一次表空間校驗,等于校驗了 2 遍。不過 MySQL 8.0 里多了一個特性,即表數量超過 5W 時,會啟用多線程掃描,加快表空間校驗過程。

fbb1b695acc3f2faba36b5bf1d9b3a5e.png

MySQL 8.0.21 開始可以通過innodb_validate_tablespace_paths參數關閉正常啟動時的表空間校驗過程。

4da9a97943f54bbe633d5390d4bbb197.png

六、如何跳過校驗

MySQL 5.7 下有方法可以跳過崩潰恢復時的表空間校驗過程嘛?查閱了資料,方法主要有兩種:1. 配置 innodb_force_recovery可以使 srv_force_recovery != 0 ,那么 validate = false,即可以跳過表空間校驗。實際測試的時候設置 innodb_force_recovery =1,也就是強制恢復跳過壞頁,就可以跳過校驗,然后重啟就是正常啟動了。通過這種臨時方式可以避免崩潰恢復后非常耗時的表空間校驗過程,快速啟動 MySQL,個人目前暫時未發現有什么隱患。2. 使用共享表空間替代獨立表空間這樣就不需要打開 N 個 ibd 文件了,只需要打開一個 ibdata 文件即可,大大節省了校驗時間。自從聽了姜老師講過使用共享表空間替代獨立表空間解決 drop 大表時性能抖動的原理后,感覺共享表空間在很多業務環境下,反而更有優勢。

bool validate = recv_needed_recovery && srv_force_recovery == 0;

//跳過表空間校驗

validate = false

//執行表空間校驗

validate = true

臨時冒出另外一種解決想法,即用 GDB 調試崩潰恢復,通過臨時修改 validate 變量值讓 MySQL 跳過表空間驗證過程,然后讓 MySQL 正常關閉,重新啟動就可以正常啟動了。但是實際測試發現,如果以 debug 模式運行,確實可以臨時修改 validate 變量,跳過表空間驗證過程,但是 debug 模式下代碼運行效率大打折扣,反而耗時更長。而以非 debug 模式運行,則無法修改 validate 變量,想法破滅。

b9e24476f7e79f429cdb012a492d29fe.png

c9777a222b3283e275afa5b8e46172a2.png

附錄:

https://dev.mysql.com/worklog/task/?id=7142

http://blog.symedia.pl/2015/11/mysql-56-and-57-crash-recovery.html

https://www.percona.com/community-blog/2019/07/23/impact-of-innodb_file_per_table-option-on-crash-recovery-time/

https://jira.mariadb.org/browse/MDEV-18733

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/396528.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/396528.shtml
英文地址,請注明出處:http://en.pswp.cn/news/396528.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

surfaceview結束后怎么處理_污泥壓濾機處理后的污泥怎么處置

在污泥處理處置中,污泥壓濾機處理污泥只是對污泥進行脫水,并沒有實現污泥資源化處置。再進行污泥“減量化、無害化、資源化”處理時,許多企業用污泥壓濾機對污泥脫水處理后就不知道怎么繼續處置了,從而使污泥餅無處可去&#xff0…

js數組詳解

1,什么是數組數組是值得有序集合,每個值叫做一個元素,而每個元素在數組中有一個位置,以數字表示,稱為索引。js的數組是無類型的,數組元素可以是任意類型,同一個數組中的不同元素可能是對象或數組…

[轉載]linux內存映射mmap原理分析

轉自:http://blog.csdn.net/yusiguyuan/article/details/23388771 內存映射,簡而言之就是將用戶空間的一段內存區域映射到內核空間,映射成功后,用戶對這段內存區域的修改可以直接反映到內核空間,同樣,內核空…

判斷一個指針有沒有free_Free Code Camp的每個人現在都有一個檔案袋

判斷一個指針有沒有freeby freeCodeCamp通過freeCodeCamp Free Code Camp的每個人現在都有一個檔案袋 (Everyone at Free Code Camp now has a Portfolio) Note: we originally published this on our now-defunct blog in January of 2015.注意:我們最初是在2015年…

冒泡、快速排序小結

1.冒泡排序 (1) 比較領近的兩個數 (2) 如果左邊的比右邊的數字大,則交換位置 (3) 向右移動一位,繼續比較相鄰的兩個數 排序示例: 一輪排序結束后,最大值的位置已經移動最右端,再次如此循環,最終經過n-1次則…

python中until函數_等待應用程序窗口:python中的pywinauto.timings.WaitUntilPasses

我試圖在pywinauto中使用waituntilpasses來給應用程序時間打開一個新窗口.我已使用SWAPY識別窗口詳細信息.為了進行測試,我手動打開了子窗口,因此WaitUntilPasses應該立即看到該窗口,但是沒有看到.語法顯示為OK,因為我可以找到并打印find_windows的輸出,如下所示:xx…

synchronized 異常_由淺入深,Java 并發編程中的 Synchronized

synchronized 作用synchronized 關鍵字是 Java 并發編程中線程同步的常用手段之一。1.1 作用:確保線程互斥的訪問同步代,鎖自動釋放,多個線程操作同個代碼塊或函數必須排隊獲得鎖,保證共享變量的修改能夠及時可見,獲得…

mysql正則通配符全解_mysql正則表達式與通配符

擴展正則表達式的一些字符是: “.”匹配任何單個的字符。 一個字符類“[...]”匹配在方括號內的任何字符。例如,“[abc]”匹配“a”、“b”或“c”。為了命名字符的一個范圍,使用一個“-”。“[a-z]”匹配任何小寫字母,而“[0-9…

dos常用文件操作命令

1、DIR 含義: 顯示指定目錄下的文件和子目錄列表 類型: 內部命令 格式: DIR[drive:][path][filename][/p][/w][/A[[:]attributes]][/O[[:]sortorder]][/S][/B][/L] 舉例: DIR DIR D:\px2 DIR D:\px2\*.txt DIR /A:D /O:D 2、COPY…

使您的Java代碼聞起來很新鮮

by Marco Massenzio由Marco Massenzio 使您的Java代碼聞起來很新鮮 (Make your Java code smell nice and fresh) A few years ago I joined a startup working on a cloud enterprise service that was originally built by an offshore team.幾年前,我加入了一家…

MySQL時間戳與日期格式的相互轉換

MySQL時間戳與日期格式的相互轉換,PHP時間戳與日期格式的相互轉換 MySQL: 獲取當前時間SELECT NOW(); // 2018/10/11 14:22:51 時間日期格式轉換成時間戳格式,UNIX_TIMESTAMP()SELECT UNIX_TIMESTAMP(NOW()); // 1539238930 時間戳格式轉換成時間日期格式…

Linux內存分配機制之伙伴系統和SLAB

轉載請注明原文地址:http://www.cnblogs.com/ygj0930/p/6539590.html 內核內存管理的一項重要工作就是如何在頻繁申請釋放內存的情況下,避免碎片的產生。這就要求內核采取靈活而恰當的內存分配策略。通常,內存分配一般有兩種情況&#xff1a…

this.$modal.confirm 自定義按鈕關閉_自定義函數,讓你玩轉Excel得心應手

讓“自動更正”輸入統一的文本,你是不是經常為輸入某些固定的文本,如《電腦報》而煩惱呢?那就往下看吧。1.執行“工具→自動更正”命令,打開“自動更正”對話框。2.在“替換”下面的方框中輸入“pcw”(也可以是其他字符,“pcw”用小寫),在“替換為”下面的方框中輸…

php mysql 排名算法_MySQL PHP:優化排名查詢和計數子查詢

這是原始數據,并希望根據得分(count(tbl_1.id))對它們進行排名.[tbl_1]id | name1 | peter2 | jane1 | peter2 | jane3 | harry3 | harry3 | harry3 | harry4 | ron因此,制作臨時表(tbl_2)來計算每個id的分數.SELECT id, name, COUNT( id ) AS scoreFROM tbl_1GROUP BY idORDER…

CCF-CSP 最大的矩形

問題描述在橫軸上放了n個相鄰的矩形,每個矩形的寬度是1,而第i(1 ≤ i ≤ n)個矩形的高度是hi。這n個矩形構成了一個直方圖。例如,下圖中六個矩形的高度就分別是3, 1, 6, 5, 2, 3。請找出能放在給定直方圖里面積最大的矩…

Stack Overflow 2016年對50,000名開發人員進行的調查得出的見解

Today, Stack Overflow released the results of their 2016 survey of more than 50,000 developers.今天,Stack Overflow發布了他們2016年對50,000多名開發人員進行的調查的結果。 I’ve combed through this big document to bring you the most surprising ins…

web管理

1.站點根目錄下查找是否被放置webshell***根據語句判斷是不是PHP***腳本# find /storage/www/ -name "*.php" | xargs grep-in --color "eval("# grep -i --include*.php -r system\s*\( /storage/www/2.統計訪問日志中來自同ip出現的次數分析盜鏈、***、機…

MySQL的主從復制云棲社區_MySQL-主從復制

前言前篇說了作為運維在數據庫塊最起碼要會兩大技能,今天來說說第二技能--主從復制隨著業務的增長,一臺數據庫服務器以滿足不了需求了,負載過重,這時候就需要減壓,實現負載均衡讀寫分離,一主一從或一主多從…

數據存儲(SharedPreferences存儲)

SharedPreferences是通過 鍵值對 的方式存儲數據SharedPreferences是通過鍵值對的方式存儲的 將數據存儲到SharedPreferences中有3種方法:1.Context類中的getSharedPreferences()方法2.Activity類中的getPreferences()方法3.PreferencesManager類中的getDefaultShar…

編程程序的名稱要記住嗎_學習編程時要記住的5件事

編程程序的名稱要記住嗎by Kurt由庫爾特 學習編程時要記住的5件事 (5 Things to Remember When You’re Learning to Program) Learning to program is challenging. Aside from choosing a language or setting up a development environment that you know nothing about, t…