對(duì)HTTP請(qǐng)求接口資源下載時(shí)間過(guò)長(zhǎng)的問(wèn)題分析
問(wèn)題描述
我司某產(chǎn)品線有指定業(yè)務(wù)接口customQuery在線上環(huán)境中,與首頁(yè)一起打開(kāi)時(shí)下載數(shù)據(jù)的時(shí)間明顯過(guò)長(zhǎng)(平均可以達(dá)到2s)
注:
- “與首頁(yè)一起打開(kāi)” 的含義是指用戶進(jìn)入WEB系統(tǒng)后會(huì)首次加載的主頁(yè)面,該主頁(yè)會(huì)提前請(qǐng)求customQuery數(shù)據(jù),以用于顯示首頁(yè)中的列表數(shù)據(jù)。
- 正常的想法會(huì)第一時(shí)間認(rèn)為是剛進(jìn)入首頁(yè)請(qǐng)求多,導(dǎo)致的下載速度慢,這個(gè)自然不是這個(gè)原因,要不然也不會(huì)專門寫(xiě)這些內(nèi)容,后面會(huì)講到。
- 下文中我會(huì)盡量?jī)H針對(duì)問(wèn)題本身,不摻雜業(yè)務(wù)邏輯進(jìn)行表述,并盡可能的做到描述清晰,準(zhǔn)確。不過(guò)個(gè)人表達(dá)力及知識(shí)儲(chǔ)備難免會(huì)有盲區(qū),下文如有描述不當(dāng)或有事實(shí)錯(cuò)誤的地方,希望大家可以直接悉心指出。
- 這里需要單獨(dú)說(shuō)明下因?yàn)橹耙呀?jīng)發(fā)過(guò)一篇關(guān)于customQuery請(qǐng)求gzip壓縮的帖子,而這里講的是2個(gè)沒(méi)有關(guān)系的東西,不用聯(lián)系在一起。
先直接上問(wèn)題請(qǐng)求的截圖

如上圖323K的數(shù)據(jù)下載用了近2s,明顯是出問(wèn)題了。
該接口有在數(shù)據(jù)翻頁(yè)時(shí)也會(huì)觸發(fā),不過(guò)下載時(shí)間表現(xiàn)正常。(如下圖,同樣的軟硬件條件,在其他場(chǎng)景下,同樣的參數(shù)拉取同一個(gè)接口的情況)
上圖是翻頁(yè)的場(chǎng)景(因?yàn)槭橇斜頂?shù)據(jù),默認(rèn)進(jìn)入打開(kāi)第一頁(yè),也可以自己觸發(fā)翻頁(yè)到其他頁(yè)或回到第一頁(yè)),也就是說(shuō)只有在首頁(yè)中被調(diào)用時(shí)下載時(shí)間異常,在正常TAB頁(yè)中切換翻頁(yè)數(shù)據(jù)下載表現(xiàn)都很正常。
還有一個(gè)細(xì)節(jié),這個(gè)接口在測(cè)試或預(yù)發(fā)環(huán)境表現(xiàn)都是正常的,沒(méi)有出現(xiàn)下載時(shí)間過(guò)長(zhǎng)的問(wèn)題,這也從側(cè)面證明了并不是因?yàn)槭醉?yè)數(shù)據(jù)量大導(dǎo)致下載慢,通過(guò)查看各個(gè)整個(gè)過(guò)程的請(qǐng)求時(shí)間線也能明顯看出,在出問(wèn)題的時(shí)間斷,并沒(méi)有很多數(shù)據(jù)資源正在傳輸。
排除服務(wù)端問(wèn)題
為了排除服務(wù)端的問(wèn)題,自己構(gòu)建了測(cè)試程序簡(jiǎn)單模擬了下面場(chǎng)景。
- 同一請(qǐng)求順序發(fā)送10次,結(jié)果如下(下載時(shí)間全部保持在300ms以下)

通過(guò)上面的測(cè)試不難看出無(wú)論是順序發(fā)送,或同一個(gè)客戶端同時(shí)并行請(qǐng)求該請(qǐng)求資源的情況下,下載速度都不會(huì)下降到超過(guò)1s的水平。
Chrome DevTools 里可以看到當(dāng)前瀏覽器默認(rèn)同一個(gè)域名雖也是同時(shí)維持著6個(gè)http1.1鏈接,但除了目標(biāo)接口,其他5個(gè)請(qǐng)求都會(huì)非常快的完成(其他響應(yīng)大多小于1kb,不會(huì)占用太多帶寬)
雖然這樣想,但是現(xiàn)在也只能暫時(shí)懷疑是網(wǎng)絡(luò)方面的問(wèn)題了,為了證實(shí)自己的猜想,需要分析TCP原始報(bào)文。
注:本文并不闡述如何解決問(wèn)題,主要通過(guò)各種事實(shí)數(shù)據(jù)證明問(wèn)題出現(xiàn)在哪一個(gè)點(diǎn),從而將問(wèn)題轉(zhuǎn)到正確的責(zé)任人。因?yàn)橐话惚容^詭異的問(wèn)題如果不能確認(rèn)是問(wèn)題具體是出在哪一塊(服務(wù)端,運(yùn)維,前端,嵌入式),那任何一方在工作壓力已經(jīng)如此大的情況下難免會(huì)本能的認(rèn)為是其他人的問(wèn)題,最后的結(jié)果就是,問(wèn)題長(zhǎng)時(shí)間都得不到解決。不過(guò)如果有充足是事實(shí)證據(jù)證明問(wèn)題出在哪里,那通常負(fù)責(zé)那一塊的同學(xué)還是會(huì)盡力去解決的。
排查網(wǎng)絡(luò)問(wèn)題
準(zhǔn)備工作
為了配合Wireshark分析TCP報(bào)文我們需要使用Chrome的【Capture Network Log】直接在chrome中訪問(wèn) chrome://net-export/ 即可以打開(kāi)。
(Capture Network Log 的使用見(jiàn) https://support.google.com/chrome/a/answer/3293821?hl=en 僅僅是用還是比較容易的)
如下圖,在把Capture Network Log啟動(dòng)后,再次觸發(fā)首頁(yè)加載,DevTools顯示下載時(shí)間依然很長(zhǎng)。

剛剛network logs里的數(shù)據(jù)我們可以在netlog viewer里打開(kāi)(https://netlog-viewer.appspot.com/ 這是官方的在線日志分析器,訪問(wèn)這個(gè)鏈接您可能需要“梯子”)

如上圖,通過(guò)查看netlog viewer 里的SOCKET_BYTES_SENT記錄我們不難發(fā)現(xiàn)這個(gè)鏈接其實(shí)一共發(fā)送了4次HTTP應(yīng)用層請(qǐng)求(分別在第26ms,第119ms,第153ms,第184ms 注意這里使用的是相對(duì)時(shí)間)
通過(guò)計(jì)算保留到秒的絕對(duì)時(shí)間分別為35.528;35.621;35.655;35.686 (實(shí)際是最后一個(gè)才是我們的目標(biāo)請(qǐng)求,通過(guò)chrome時(shí)間線或響應(yīng)的大小可以很容易的確認(rèn)這個(gè)點(diǎn))
netlog viewer對(duì)的上去的(因?yàn)檎?qǐng)求實(shí)際上都很小,一個(gè)報(bào)文長(zhǎng)度內(nèi)就能發(fā)完)
目標(biāo)流量確認(rèn)了,現(xiàn)在我們可以安心的去分析TCP報(bào)文了
1:首先懷疑滑動(dòng)窗持續(xù)收縮,導(dǎo)致后面接收效率急劇下降
Wireshark提供的流圖形我們可以直觀的看到滑動(dòng)窗口在整個(gè)TCP數(shù)據(jù)流里的變化趨勢(shì)(當(dāng)然在外面報(bào)文列表里也能直接看出來(lái))
2:而后是擁塞窗口cwnd,會(huì)不會(huì)是發(fā)送端因?yàn)閬y序或超時(shí)導(dǎo)致服務(wù)器當(dāng)前鏈路的cwnd下降而主動(dòng)降速
因?yàn)閏wnd是發(fā)送端本地維護(hù)的,我們無(wú)法像Win窗口一樣在Wireshark里直接看到,不過(guò)我們可以通過(guò)觀察流量包的狀態(tài)得出初步的判斷。(分析在沒(méi)有ACK確認(rèn)的情況下可以發(fā)送多少數(shù)據(jù))
目標(biāo)請(qǐng)求response一共323KB(服務(wù)端回我們的包一個(gè)為1460字節(jié))理論一共大概會(huì)回復(fù)我們200多個(gè)包(通過(guò)過(guò)濾器我們可以準(zhǔn)確統(tǒng)計(jì)出229個(gè)含有有效數(shù)據(jù)的回包,當(dāng)然包括少量的TLS握手及前3個(gè)請(qǐng)求的回包)
如果按默認(rèn)擁塞窗口閥值ssthresh取65532,最差會(huì)在第45個(gè)包左右(每個(gè)報(bào)文段都充滿的情況下)就會(huì)完成慢啟動(dòng)進(jìn)入擁塞避免狀態(tài)。
3:后面想到的就是數(shù)據(jù)包亂序,或丟包
因?yàn)闊o(wú)論是丟包還是亂序,最終都會(huì)反應(yīng)到cwnd下降,發(fā)送效率降低,不過(guò)從數(shù)據(jù)包列圖表來(lái)看并沒(méi)有發(fā)生這些情況。
為了分析丟包及亂序?qū)Y源下載的影響,實(shí)際測(cè)試的時(shí)候有意創(chuàng)造了較差網(wǎng)絡(luò),分析了這些有很多亂序及重傳的情況,如下圖是一次有亂序的流量。(與前文中的截圖不是同一個(gè)流量數(shù)據(jù),該圖是專門選取的網(wǎng)絡(luò)條件較差的情況)
可以明顯看出來(lái),即使發(fā)生了丟包及亂序,TCP恢復(fù)的都非常的快,絕不會(huì)把下載速度拖到超過(guò)1s。
確認(rèn)問(wèn)題
明確原因
反復(fù)查看了多組測(cè)試數(shù)據(jù)包,怎么看都覺(jué)得流量是正常的,鏈路上的數(shù)據(jù)包及他們的確認(rèn)包,還包括他們從異常狀態(tài)中的恢復(fù)過(guò)程都很正常,完全看不不同尋常的東西。
有的時(shí)候陷進(jìn)去了是很難拔出來(lái)的,之前一直認(rèn)為是運(yùn)維的問(wèn)題,所以竭盡全力的去尋找網(wǎng)絡(luò)上的問(wèn)題。
會(huì)不會(huì)是最開(kāi)始判斷錯(cuò)了,恍然大悟,如果網(wǎng)絡(luò)都是正常的那不可能是超過(guò)1s的傳輸時(shí)間啊,200多個(gè)包一次15個(gè)間隔大概10ms,那發(fā)送及確認(rèn)的時(shí)間絕不會(huì)超過(guò)200ms才對(duì)!
這個(gè)時(shí)候我才開(kāi)始懷疑chrome的數(shù)據(jù)(因?yàn)橹坝?jì)算TTFB的時(shí)間chrome與wireshark的時(shí)間一致,后面就再也沒(méi)有懷疑過(guò)chrome的時(shí)間,也沒(méi)有特意去對(duì)比后面的時(shí)間點(diǎn))
驗(yàn)證問(wèn)題
為了驗(yàn)證這個(gè)的結(jié)論可以使用使用了常用的代理軟件(charles及fiddler)他們都會(huì)有獨(dú)立的時(shí)間線統(tǒng)計(jì)功能。
其實(shí)到現(xiàn)在已經(jīng)可以下結(jié)論是客戶端的的問(wèn)題(前端)。不過(guò)因?yàn)檫@個(gè)請(qǐng)求其實(shí)在瀏覽器除首頁(yè)的其他場(chǎng)景或著使用其他客戶端直接請(qǐng)求下載速度都是正常的,出問(wèn)題的那次請(qǐng)求又是預(yù)加載的請(qǐng)求(同時(shí)還會(huì)有好幾個(gè)請(qǐng)求會(huì)被一起發(fā)送),所以乍一看總會(huì)覺(jué)得是網(wǎng)絡(luò)方面的問(wèn)題,當(dāng)然這個(gè)上文中的內(nèi)容已經(jīng)證明了,完全不是網(wǎng)絡(luò)的問(wèn)題。不過(guò)要讓前端同學(xué)“誠(chéng)懇”的接受這個(gè)是自己的問(wèn)題并想辦法修復(fù)它,可能還需要我們進(jìn)一步指出問(wèn)題出在了什么地方(萬(wàn)一有同學(xué)把問(wèn)題直接推給chrome那不就無(wú)解了么)。
通過(guò)上文的描述我們可以發(fā)現(xiàn)響應(yīng)回包已經(jīng)在200ms內(nèi)全部被客戶端socket確認(rèn),但是chrome似乎認(rèn)為是1,2s。
排除其他因素
還有一個(gè)細(xì)節(jié),因?yàn)橄螺d時(shí)間變長(zhǎng)在測(cè)試或預(yù)發(fā)環(huán)境表現(xiàn)正常,因此一開(kāi)始我按自己的經(jīng)驗(yàn)認(rèn)為是運(yùn)維的問(wèn)題(服務(wù)器,網(wǎng)絡(luò),nginx)所以一直在試圖證明自己的錯(cuò)誤的想法,偏執(zhí)的去找數(shù)據(jù)流量的茬,同時(shí)也沒(méi)有懷疑過(guò)chrome統(tǒng)計(jì)的數(shù)據(jù)可能不是真實(shí)的網(wǎng)絡(luò)時(shí)間,導(dǎo)致整個(gè)過(guò)程花了很長(zhǎng)時(shí)間。














浙公網(wǎng)安備 33010602011771號(hào)