新聞中心
背景

鎮(zhèn)巴ssl適用于網(wǎng)站、小程序/APP、API接口等需要進行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為成都創(chuàng)新互聯(lián)公司的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:028-86922220(備注:SSL證書合作)期待與您的合作!
有一個業(yè)務(wù)需要分 1000 個庫,每一個庫中都有 80 個表,總共就是 80000 * 2 個文件。文件使用率還挺高,大概是 60000 * 2。
這個業(yè)務(wù)采用的高可用架構(gòu)是 MMM,由于集群機器在硬件檢查時發(fā)現(xiàn)有問題,必須要換掉。于是想了一個比較簡單、影響面較小的方法去解決,就是找了另外兩臺機器遷移過去。同時,要求這四臺機器屬于同一個網(wǎng)段,VIP(虛擬 IP 地址)在機器之間可以漂移,這樣業(yè)務(wù)就不需要修改 IP 地址即可遷移,相當于兩次主從切換過程。
切換方案如圖 16.1 所示。
從圖 16.1 中可以看到,切換過程很簡單,如下三步。
- 先將原來的寫節(jié)點(db1)與一個新的節(jié)點(db3)切換成一套集群,也就是把在 db2 上面的 VIP(讀流量)切換到 db3 上面,此時 db1 與 db3 組成一套新集群。
- 接著將 db1 和 db3 的角色互換,讓 db3 成為寫節(jié)點,db1 成為讀節(jié)點。
- 最后,再將 db1 讀節(jié)點上面的 VIP(讀流量)切換到 db4 上面,此時新的集群就是 db3 和 db4,db3 為寫節(jié)點,已經(jīng)切換完成。這樣的變更是晚上做的。做好之后,觀察了一段時間,發(fā)現(xiàn)沒有什么問題(因為壓力小),所以覺得事情完成了,睡吧。 第二天上班之后,業(yè)務(wù)反映說遷移之后,數(shù)據(jù)庫比原來慢了 10 倍(10 倍啊!感覺不可思議)。詢問了一番,說沒有任何變更,只是做了遷移之后就成這樣了。同時經(jīng)過觀察,只有寫庫的讀操作變慢了,而讀庫的讀是不慢的。最后,業(yè)務(wù)已經(jīng)受不了了,要求切換回去。還好,db1 還正在從 db3 復制,做了一個回退操作,把寫掛在 db1 上面,把讀掛在 db3 上面。神奇的是,問題解決了!好吧,那就先這樣,走出去的路不能回頭,總是要遷出去的,所以先在新舊兩臺機器上面掛著,查明原因后再切換回去(這樣少做一步)。
以上是背景。
問題分析
環(huán)境對比
- db1 寫入時,db1 寫不慢,讀不慢,db3 也不慢。
- db3 是新的硬件,db1 是老的、有問題的硬件。
- db3 切換成寫之后,在慢查詢文件中明顯看到很多慢查詢(使用相同的語句查詢,原來是 50ms,現(xiàn)在是 500ms),和監(jiān)控是一致的。
- db1 和 db3 配置文件有差別,如圖 16.2 所示(左邊是 db3 的,右邊是 db1 的)。
其他方面,環(huán)境完全相同,業(yè)務(wù)方面沒有任何更改,重現(xiàn)慢的現(xiàn)象,只是需要切換而已。
圖 16.3 是切換過程中的監(jiān)控圖,高起來的就是把流量切換到 db3 的情況,處于低谷的就是切換到 db1 的情況,效果非常明顯,慢得立竿見影,好神奇!
原因分析
- 從對比中可以得知,db1 是正常的(以前長時間在這個機器上跑,沒有問題),而 db3 是不正常的。這個業(yè)務(wù)目前是讀多寫少,現(xiàn)在的現(xiàn)象是讀慢。因為寫少,沒有發(fā)現(xiàn)慢,就不考慮了。
- 接著就是硬件的區(qū)別,二者都是 PCI-e 卡,老的、壞的概率比較大,從經(jīng)驗上來看新的會比較好,這是一個值得懷疑的點。但實際上,針對這個問題,找到了新卡的技術(shù)人員進行分析,將寫切換到 db3 上之后觀察,發(fā)現(xiàn) IO 非常小,能看到的監(jiān)控指數(shù)都非常正常。(他們也很納悶。)
- 除此之外,唯一的區(qū)別就是二者的配置了,但從圖 16.3 中可以看到,沒有一個參數(shù)可以影響到讓數(shù)據(jù)庫的響應(yīng)時間是原來的 10 倍。
但上面這些都只是分析,硬件測試之后,沒有發(fā)現(xiàn)問題(也不能說就不是硬件的問題,一直吊在那里)。那只剩下配置了,所以接下來從這里入手吧,希望能成功!
那么,再找一個夜深人靜的夜晚……
案例解決
首先要做的事情是,把 db3 的讀流量切換到 db1,然后把配置完全換成 db1 的配置,將數(shù)據(jù)庫重啟,然后上線。此時,db1 是寫節(jié)點,db3 是讀節(jié)點,最神奇的時刻即將到來。
切換之后,經(jīng)過觀察,竟然沒有問題了。問題已經(jīng)解決,那么說明還是上面列出來的配置差別引起的問題。
那么解決之后,下面的工作就是重復一開始的工作,把 db1 下線,讓 db4 上線。此刻,之前的遷移工作已經(jīng)完成,線上服務(wù)沒有問題。
但……開發(fā)同學,能給我半個小時,讓我看看是哪個參數(shù)引起的么? 得到的回答是:“迅速點,就這一次,給你 20 分鐘。”
把最有可能的參數(shù)找出來,比如字符集(實際上,上面列出的每一個,我們認為都不會有多大影響),考慮到字符集是不可動態(tài)修改的參數(shù),所以先把這個改了。重啟,然后一個一個地動態(tài)修改、業(yè)務(wù)重啟重連等,都沒有發(fā)現(xiàn)。修改的這些參數(shù)包括:sql_mode、join_buffer_size、max_heap_size、sort_buffer_size,這些都沒有影響。
結(jié)果已經(jīng)說好的只有這一次,那就這樣吧,任務(wù)成功完成,問題解決失敗。
然而,這個問題“才下手頭,卻上心頭”,總有一件事放心不下,約吧。 和開發(fā)商量了一下,我們想解決這個問題,知道其所以然,防止在其他業(yè)務(wù)上出現(xiàn)同樣的問題。好吧,再給你們一次機會(來之不易啊)。
那么,再找一個夜深人靜的夜晚……這次的月亮好像比上次更圓一些,是好日子的征兆么?
操作之前,還簡單規(guī)劃了一下,下面是當時的一個計劃步驟。
^* 黑體的表示已經(jīng)專門測試過,沒有影響
步驟如下。
考慮到先重現(xiàn)問題,首先應(yīng)該全部使用新配置測試一次,確定問題是否還存在。
因為重點考慮問題是因為 sql_mode 引起的,所以第二次只將這個參數(shù)改為老配置,這樣就可以測試出其他配置組合時有問題,或者是沒有問題,從而得出結(jié)論是 sqlmode 的問題。
如果上面還沒有找到問題原因,那么就是除了 sql_mode 之外的其他參數(shù)組合出了問題(如果沒有,則見鬼了)。此時,通過二分法測試,先測試 innodb_flush_log_at_trx_commit、innodb_open_files、sort_buffer_size 三個參數(shù)。
如果發(fā)現(xiàn)上一步有問題,則再進行二分;如果沒有發(fā)現(xiàn)問題,則對 sync_binlog、join_buffer_size、tmp_table_size 進行二分。
如果能走到這里,那也是醉了。
再說吧。
按照步驟,一步步地開始做。
首先使用有問題的配置,測試一遍,發(fā)現(xiàn)是老樣子,還是有問題的(真是幸運,問題還存在)。
把除了 sql_mode 之外的所有參數(shù)改成新的,其他都用老配置,測試發(fā)現(xiàn)沒有問題。
做完了,也是沒有問題。
做完了,還是沒有問題。
我醉了。
此時當事人已經(jīng)搞不清楚了,難道是某兩個的組合會導致出現(xiàn)這樣的問題?如果是這樣的話,那情況就太多了,天已經(jīng)亮了,很累,放棄吧!
就在想放棄的時候,突然有一種新的思路。在有問題的基礎(chǔ)上,把所有經(jīng)過測試沒有影響的可以動態(tài)修改的參數(shù)改成與 db1 相同的參數(shù),這樣應(yīng)該是最少量的可以影響到性能的參數(shù)組合了。此時,在 db1 與 db3 實例上分別執(zhí)行 show variables,全量導出變量,進行對比,發(fā)現(xiàn)有幾個參數(shù)的區(qū)別(左邊是老的 db1,右邊是新的 db3),如圖 16.4 所示。
此時,我們做了最后的掙扎,已經(jīng)只剩下這 6 個了,看上去還是不會有什么影響,有些已經(jīng)試過了,再隨便試一次吧。二分查找,從下面開始找了三個參數(shù),下線、重啟、上線……發(fā)現(xiàn)問題竟然奇跡般地存在。而此時只剩下了三個參數(shù),其中一個參數(shù)是 sync_binlog,有問題的是 0,肯定不會影響啊。只能定位到剩下的兩個了,可以看到倒數(shù)第二個是一個 performance_schema 的參數(shù),配置文件中沒有設(shè)置,是默認的,可以忽略。于是,把問題定位到 open_files_limit 了。
此時,再做最后一次,只剩下 open_files_limit 的區(qū)別了。結(jié)果還是有問題,說明就是這個參數(shù)了。
回過頭來想了一下,其實當初看區(qū)別的時候,這兩個參數(shù)就在配置文件中,只是看著 13 萬和 15 萬相差不大,就忽略了。好吧,問題已經(jīng)解決,找到了原因,天亮了,回家吧。
已經(jīng)查到了是 open_files_limit 的原因。那么,究竟為什么在一個參數(shù)相差這么小的情況下會影響 10 倍的性能呢?查查源碼!
通過 sysbench,創(chuàng)建 60000 個表,每個表 10000 行,在只讀模式下,發(fā)現(xiàn)設(shè)置為 130000 時,QPS 可以達到 20000,而設(shè)置為 150000 的時候,QPS 只有 4000 左右。問題重現(xiàn)了,就簡單多了。
此外,還有一個額外的發(fā)現(xiàn)。如果設(shè)置為 150000 之后,重啟數(shù)據(jù)庫,非常慢,大概需要 1 分鐘,而設(shè)置為 130000 之后,只需要 10 秒左右。查看了一下在很慢的過程中 mysqld 的線程情況。其中,在啟動的過程中,有一個線程長時間都基本處于同一個堆棧,使用 pstack mysqldpid 查看,如圖 16.5 所示。
還有一個發(fā)現(xiàn)就是,當設(shè)置 open_files_limit 為相同的時候,performance_schema_max_file_instances 參數(shù)也相同了,并且這個參數(shù)沒有設(shè)置過。那么,通過源碼發(fā)現(xiàn),這個參數(shù)竟然是通過 open_files_limit 值來設(shè)置的。如果 open_files_limit 值設(shè)置得比較大(這樣就可以忽略掉其他影響條件,比如 max_connection 等),performance_schema_max_file_instances 的值直接就是從 open_files_limit/0.65 得來的(源碼對應(yīng)函數(shù) apply_load_factor)。這樣就知道了,130000/0.65 正好是 200000,150000/0.65 正好是 230770,與圖 16.4 所示相符合。
另外,通過測試發(fā)現(xiàn),如果單獨設(shè)置 performance_schema_max_file_instances 為不相同的值,而將 open_files_limit 設(shè)置為相同,性能還是不一樣。從而可以確定與 open_files_limit 參數(shù)實際上沒有什么關(guān)系,只是 performance_schema_max_file_instances 使用了默認值,它的值就來源于 open_files_limit/0.65 了,這樣間接影響了 performance_schema_max_file_instances 值,突然有種“隔山打?!钡母杏X。
還有一個發(fā)現(xiàn),如果將 performance_schema_max_file_instances 設(shè)置為 200000、210000、220000、230000、240000、300000 等,性能都是差不多的,唯獨設(shè)置為 230770 是有問題的。仔細研究之后發(fā)現(xiàn),performance_schema_max_file_instances 最終影響的是 performance_schema 數(shù)據(jù)庫中的 file_instances 表,這個表中的數(shù)據(jù)是通過一個 HASH 表來緩存的,而這個參數(shù)決定的是該 HASH 表的大小。
后面又做了一個非常無聊的測試,是 performance_schema_max_file_instances 值與 QPS 的對比,如圖 16.6 所示。
至此,一切都豁然開朗了。結(jié)合上面非常慢的堆棧,以及將 performance_schema_max_file_instances 設(shè)置為不同值的現(xiàn)象,可以確定,這個問題最終是 HASH 算法的問題。當 HASH 桶大小為一個比較好看的數(shù)值時,這個算法就非常快,而如果是一個比較零碎的值時,算法就非常慢了,會導致響應(yīng)時間是原來的 10 倍。
總結(jié)
這個問題,確實很詭異,萬萬沒有想到是相差那么小的一個變量的問題(以至于一開始就被忽略了)。
這個問題,比較少見,只有表比較多的時候才會比較明顯(因為表比較少的時候,算法相對比較穩(wěn)定)。
這個問題,查明了,其實就是一個算法方面的 BUG。
這個問題,簡單的規(guī)避方法是單獨設(shè)置 performance_schema_max_file_instances 值為 0,或者設(shè)置 performance_schema_max_file_instances 為一個比較好看的數(shù)值,又或者設(shè)置 open_files_limit 為 0.65 的整數(shù)倍,這樣都不會有問題。
這個問題,雖然影響比較小,但我們對問題的探索精神不能沒有,要了然于胸。
這個問題,到此為止。
名稱欄目:大量MySQL表導致服務(wù)變慢的問題
URL鏈接:http://fisionsoft.com.cn/article/ccsodgs.html


咨詢
建站咨詢
