自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

大量MySQL表導(dǎo)致服務(wù)變慢的問題

數(shù)據(jù)庫 MySQL

背景

有一個(gè)業(yè)務(wù)需要分 1000 個(gè)庫,每一個(gè)庫中都有 80 個(gè)表,總共就是 80000 * 2 個(gè)文件。文件使用率還挺高,大概是 60000 * 2。

這個(gè)業(yè)務(wù)采用的高可用架構(gòu)是 MMM,由于集群機(jī)器在硬件檢查時(shí)發(fā)現(xiàn)有問題,必須要換掉。于是想了一個(gè)比較簡單、影響面較小的方法去解決,就是找了另外兩臺機(jī)器遷移過去。同時(shí),要求這四臺機(jī)器屬于同一個(gè)網(wǎng)段,VIP(虛擬 IP 地址)在機(jī)器之間可以漂移,這樣業(yè)務(wù)就不需要修改 IP 地址即可遷移,相當(dāng)于兩次主從切換過程。

切換方案如圖 16.1 所示。

從圖 16.1 中可以看到,切換過程很簡單,如下三步。

  1. 先將原來的寫節(jié)點(diǎn)(db1)與一個(gè)新的節(jié)點(diǎn)(db3)切換成一套集群,也就是把在 db2 上面的 VIP(讀流量)切換到 db3 上面,此時(shí) db1 與 db3 組成一套新集群。
  2. 接著將 db1 和 db3 的角色互換,讓 db3 成為寫節(jié)點(diǎn),db1 成為讀節(jié)點(diǎn)。
  3. 最后,再將 db1 讀節(jié)點(diǎn)上面的 VIP(讀流量)切換到 db4 上面,此時(shí)新的集群就是 db3 和 db4,db3 為寫節(jié)點(diǎn),已經(jīng)切換完成。這樣的變更是晚上做的。做好之后,觀察了一段時(shí)間,發(fā)現(xiàn)沒有什么問題(因?yàn)閴毫π?,所以覺得事情完成了,睡吧。 第二天上班之后,業(yè)務(wù)反映說遷移之后,數(shù)據(jù)庫比原來慢了 10 倍(10 倍啊!感覺不可思議)。詢問了一番,說沒有任何變更,只是做了遷移之后就成這樣了。同時(shí)經(jīng)過觀察,只有寫庫的讀操作變慢了,而讀庫的讀是不慢的。最后,業(yè)務(wù)已經(jīng)受不了了,要求切換回去。還好,db1 還正在從 db3 復(fù)制,做了一個(gè)回退操作,把寫掛在 db1 上面,把讀掛在 db3 上面。神奇的是,問題解決了!好吧,那就先這樣,走出去的路不能回頭,總是要遷出去的,所以先在新舊兩臺機(jī)器上面掛著,查明原因后再切換回去(這樣少做一步)。

以上是背景。

問題分析

環(huán)境對比

  • db1 寫入時(shí),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 是正常的(以前長時(shí)間在這個(gè)機(jī)器上跑,沒有問題),而 db3 是不正常的。這個(gè)業(yè)務(wù)目前是讀多寫少,現(xiàn)在的現(xiàn)象是讀慢。因?yàn)閷懮?,沒有發(fā)現(xiàn)慢,就不考慮了。
  • 接著就是硬件的區(qū)別,二者都是 PCI-e 卡,老的、壞的概率比較大,從經(jīng)驗(yàn)上來看新的會比較好,這是一個(gè)值得懷疑的點(diǎn)。但實(shí)際上,針對這個(gè)問題,找到了新卡的技術(shù)人員進(jìn)行分析,將寫切換到 db3 上之后觀察,發(fā)現(xiàn) IO 非常小,能看到的監(jiān)控指數(shù)都非常正常。(他們也很納悶。)
  • 除此之外,唯一的區(qū)別就是二者的配置了,但從圖 16.3 中可以看到,沒有一個(gè)參數(shù)可以影響到讓數(shù)據(jù)庫的響應(yīng)時(shí)間是原來的 10 倍。

但上面這些都只是分析,硬件測試之后,沒有發(fā)現(xiàn)問題(也不能說就不是硬件的問題,一直吊在那里)。那只剩下配置了,所以接下來從這里入手吧,希望能成功!

那么,再找一個(gè)夜深人靜的夜晚……

案例解決

首先要做的事情是,把 db3 的讀流量切換到 db1,然后把配置完全換成 db1 的配置,將數(shù)據(jù)庫重啟,然后上線。此時(shí),db1 是寫節(jié)點(diǎn),db3 是讀節(jié)點(diǎn),最神奇的時(shí)刻即將到來。

切換之后,經(jīng)過觀察,竟然沒有問題了。問題已經(jīng)解決,那么說明還是上面列出來的配置差別引起的問題。

那么解決之后,下面的工作就是重復(fù)一開始的工作,把 db1 下線,讓 db4 上線。此刻,之前的遷移工作已經(jīng)完成,線上服務(wù)沒有問題。

但……開發(fā)同學(xué),能給我半個(gè)小時(shí),讓我看看是哪個(gè)參數(shù)引起的么? 得到的回答是:“迅速點(diǎn),就這一次,給你 20 分鐘。”

把最有可能的參數(shù)找出來,比如字符集(實(shí)際上,上面列出的每一個(gè),我們認(rèn)為都不會有多大影響),考慮到字符集是不可動態(tài)修改的參數(shù),所以先把這個(gè)改了。重啟,然后一個(gè)一個(gè)地動態(tài)修改、業(yè)務(wù)重啟重連等,都沒有發(fā)現(xiàn)。修改的這些參數(shù)包括:sql_mode、join_buffer_size、max_heap_size、sort_buffer_size,這些都沒有影響。

結(jié)果已經(jīng)說好的只有這一次,那就這樣吧,任務(wù)成功完成,問題解決失敗。

然而,這個(gè)問題“才下手頭,卻上心頭”,總有一件事放心不下,約吧。 和開發(fā)商量了一下,我們想解決這個(gè)問題,知道其所以然,防止在其他業(yè)務(wù)上出現(xiàn)同樣的問題。好吧,再給你們一次機(jī)會(來之不易啊)。

那么,再找一個(gè)夜深人靜的夜晚……這次的月亮好像比上次更圓一些,是好日子的征兆么?

操作之前,還簡單規(guī)劃了一下,下面是當(dāng)時(shí)的一個(gè)計(jì)劃步驟。

^* 黑體的表示已經(jīng)專門測試過,沒有影響

步驟如下。

考慮到先重現(xiàn)問題,首先應(yīng)該全部使用新配置測試一次,確定問題是否還存在。

因?yàn)橹攸c(diǎn)考慮問題是因?yàn)?sql_mode 引起的,所以第二次只將這個(gè)參數(shù)改為老配置,這樣就可以測試出其他配置組合時(shí)有問題,或者是沒有問題,從而得出結(jié)論是 sqlmode 的問題。

如果上面還沒有找到問題原因,那么就是除了 sql_mode 之外的其他參數(shù)組合出了問題(如果沒有,則見鬼了)。此時(shí),通過二分法測試,先測試 innodb_flush_log_at_trx_commit、innodb_open_files、sort_buffer_size 三個(gè)參數(shù)。

如果發(fā)現(xiàn)上一步有問題,則再進(jìn)行二分;如果沒有發(fā)現(xiàn)問題,則對 sync_binlog、join_buffer_size、tmp_table_size 進(jìn)行二分。

如果能走到這里,那也是醉了。

再說吧。

按照步驟,一步步地開始做。

首先使用有問題的配置,測試一遍,發(fā)現(xiàn)是老樣子,還是有問題的(真是幸運(yùn),問題還存在)。

把除了 sql_mode 之外的所有參數(shù)改成新的,其他都用老配置,測試發(fā)現(xiàn)沒有問題。

做完了,也是沒有問題。

做完了,還是沒有問題。

我醉了。

此時(shí)當(dāng)事人已經(jīng)搞不清楚了,難道是某兩個(gè)的組合會導(dǎo)致出現(xiàn)這樣的問題?如果是這樣的話,那情況就太多了,天已經(jīng)亮了,很累,放棄吧!

就在想放棄的時(shí)候,突然有一種新的思路。在有問題的基礎(chǔ)上,把所有經(jīng)過測試沒有影響的可以動態(tài)修改的參數(shù)改成與 db1 相同的參數(shù),這樣應(yīng)該是最少量的可以影響到性能的參數(shù)組合了。此時(shí),在 db1 與 db3 實(shí)例上分別執(zhí)行 show variables,全量導(dǎo)出變量,進(jìn)行對比,發(fā)現(xiàn)有幾個(gè)參數(shù)的區(qū)別(左邊是老的 db1,右邊是新的 db3),如圖 16.4 所示。

 

此時(shí),我們做了最后的掙扎,已經(jīng)只剩下這 6 個(gè)了,看上去還是不會有什么影響,有些已經(jīng)試過了,再隨便試一次吧。二分查找,從下面開始找了三個(gè)參數(shù),下線、重啟、上線……發(fā)現(xiàn)問題竟然奇跡般地存在。而此時(shí)只剩下了三個(gè)參數(shù),其中一個(gè)參數(shù)是 sync_binlog,有問題的是 0,肯定不會影響啊。只能定位到剩下的兩個(gè)了,可以看到倒數(shù)第二個(gè)是一個(gè) performance_schema 的參數(shù),配置文件中沒有設(shè)置,是默認(rèn)的,可以忽略。于是,把問題定位到 open_files_limit 了。

此時(shí),再做最后一次,只剩下 open_files_limit 的區(qū)別了。結(jié)果還是有問題,說明就是這個(gè)參數(shù)了。

回過頭來想了一下,其實(shí)當(dāng)初看區(qū)別的時(shí)候,這兩個(gè)參數(shù)就在配置文件中,只是看著 13 萬和 15 萬相差不大,就忽略了。好吧,問題已經(jīng)解決,找到了原因,天亮了,回家吧。

已經(jīng)查到了是 open_files_limit 的原因。那么,究竟為什么在一個(gè)參數(shù)相差這么小的情況下會影響 10 倍的性能呢?查查源碼!

通過 sysbench,創(chuàng)建 60000 個(gè)表,每個(gè)表 10000 行,在只讀模式下,發(fā)現(xiàn)設(shè)置為 130000 時(shí),QPS 可以達(dá)到 20000,而設(shè)置為 150000 的時(shí)候,QPS 只有 4000 左右。問題重現(xiàn)了,就簡單多了。

此外,還有一個(gè)額外的發(fā)現(xiàn)。如果設(shè)置為 150000 之后,重啟數(shù)據(jù)庫,非常慢,大概需要 1 分鐘,而設(shè)置為 130000 之后,只需要 10 秒左右。查看了一下在很慢的過程中 mysqld 的線程情況。其中,在啟動的過程中,有一個(gè)線程長時(shí)間都基本處于同一個(gè)堆棧,使用 pstack mysqldpid 查看,如圖 16.5 所示。

 

還有一個(gè)發(fā)現(xiàn)就是,當(dāng)設(shè)置 open_files_limit 為相同的時(shí)候,performance_schema_max_file_instances 參數(shù)也相同了,并且這個(gè)參數(shù)沒有設(shè)置過。那么,通過源碼發(fā)現(xiàn),這個(gè)參數(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),如果單獨(dú)設(shè)置 performance_schema_max_file_instances 為不相同的值,而將 open_files_limit 設(shè)置為相同,性能還是不一樣。從而可以確定與 open_files_limit 參數(shù)實(shí)際上沒有什么關(guān)系,只是 performance_schema_max_file_instances 使用了默認(rèn)值,它的值就來源于 open_files_limit/0.65 了,這樣間接影響了 performance_schema_max_file_instances 值,突然有種“隔山打牛”的感覺。

還有一個(gè)發(fā)現(xiàn),如果將 performance_schema_max_file_instances 設(shè)置為 200000、210000、220000、230000、240000、300000 等,性能都是差不多的,唯獨(dú)設(shè)置為 230770 是有問題的。仔細(xì)研究之后發(fā)現(xiàn),performance_schema_max_file_instances 最終影響的是 performance_schema 數(shù)據(jù)庫中的 file_instances 表,這個(gè)表中的數(shù)據(jù)是通過一個(gè) HASH 表來緩存的,而這個(gè)參數(shù)決定的是該 HASH 表的大小。

后面又做了一個(gè)非常無聊的測試,是 performance_schema_max_file_instances 值與 QPS 的對比,如圖 16.6 所示。

 

至此,一切都豁然開朗了。結(jié)合上面非常慢的堆棧,以及將 performance_schema_max_file_instances 設(shè)置為不同值的現(xiàn)象,可以確定,這個(gè)問題最終是 HASH 算法的問題。當(dāng) HASH 桶大小為一個(gè)比較好看的數(shù)值時(shí),這個(gè)算法就非??欤绻且粋€(gè)比較零碎的值時(shí),算法就非常慢了,會導(dǎo)致響應(yīng)時(shí)間是原來的 10 倍。

總結(jié)

這個(gè)問題,確實(shí)很詭異,萬萬沒有想到是相差那么小的一個(gè)變量的問題(以至于一開始就被忽略了)。

這個(gè)問題,比較少見,只有表比較多的時(shí)候才會比較明顯(因?yàn)楸肀容^少的時(shí)候,算法相對比較穩(wěn)定)。

這個(gè)問題,查明了,其實(shí)就是一個(gè)算法方面的 BUG。

這個(gè)問題,簡單的規(guī)避方法是單獨(dú)設(shè)置 performance_schema_max_file_instances 值為 0,或者設(shè)置 performance_schema_max_file_instances 為一個(gè)比較好看的數(shù)值,又或者設(shè)置 open_files_limit 為 0.65 的整數(shù)倍,這樣都不會有問題。

這個(gè)問題,雖然影響比較小,但我們對問題的探索精神不能沒有,要了然于胸。

這個(gè)問題,到此為止。

責(zé)任編輯:武曉燕 來源: 運(yùn)維派
相關(guān)推薦

2012-05-15 09:49:03

TIME_WAITMySQL

2022-12-13 10:05:13

MySQL數(shù)據(jù)庫

2024-01-15 08:57:13

MySQL高并發(fā)

2021-11-09 07:26:14

網(wǎng)速安全隱患

2009-09-02 17:25:02

郵件服務(wù)器

2020-06-10 14:10:53

服務(wù)開發(fā) 架構(gòu)

2024-04-10 14:27:03

MySQL數(shù)據(jù)庫

2011-03-31 14:05:01

mysql

2022-05-16 09:03:29

CPU服務(wù)日志

2018-11-28 06:20:52

2010-02-22 10:16:39

獨(dú)立服務(wù)器問題訪問故障

2010-10-28 09:24:26

2017-06-09 08:49:07

加載器Full GCJVM

2025-02-04 12:05:10

2010-10-13 10:34:49

MySQL修改表結(jié)構(gòu)

2023-06-06 16:54:00

2022-06-26 23:25:33

iOS蘋果系統(tǒng)

2015-06-10 10:35:51

2021-11-11 15:03:35

MySQLSQL索引

2021-11-07 23:46:32

MySQLSQL索引
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號