JB的測試之旅-記一次百度爬蟲耗時問題經歷

jb發表於2018-08-14

前言

在開始之前,想說下抱歉,如果是抱著解決問題的想法進來的話,對不起,讓你失望了,本文不會講解怎麼解決這問題,因為研發說不處理了,但本文會介紹是怎麼一路過來的,如果還感興趣,請繼續看~

上幾篇文章有介紹到,jb在負責一個seo的專案,關於seo是什麼,請點選這裡檢視;

自從專案上線後,一波三折,遇到不少坑,其中在上面那篇文章裡提及到,這裡就不說明了;

某一天,運營老大貼了這麼一張圖:

JB的測試之旅-記一次百度爬蟲耗時問題經歷
(把日期打碼了,問題不大)

從這個截圖資料上看,爬取耗時平均值932ms,最小值106ms,怎麼看都覺得合理,只是那個最大值300s的,看上去好彆扭。。

接著,我們用上面的內容反駁說,平均值看上去很正常,應該沒啥問題吧?
運營老大說,但是我們更加關心最大值,以前的產品都沒有這種情況的,最大值都不超過1000的,基本都是500-1000ms;

從這時起,開始get不同技能了~

JB的測試之旅-記一次百度爬蟲耗時問題經歷

網站介紹

在開始之前,先介紹下問題網站,www.51hjgt.com/ , 圖片就不貼了,免得有人說是廣告,這個網站的是採用node+nginx+php,其他就沒特別的;

百度資料

因為這個爬蟲是百度的,而這個爬取耗時的資料,也是百度提供的,理所當然要看看,這個值是怎麼算出來的,遺憾的是,百度的平臺沒有任何與爬取耗時有關的資訊;
既然如此,那就Google,內容為:百度爬蟲耗時很長,在搜尋的結果裡面有很多百度爬蟲的介紹,但是並沒有任何一條有直接講解到這個百度爬蟲耗時是怎麼算的~
問了很多朋友,甚至是百度內容同學,都不清楚,所以,這塊資料對於開發者來說,是一個全黑盒的玩意;
既然如此,我們就先假設,這個時間是指發起請求後,到獲取響應且渲染完內容的時間;

JB的測試之旅-記一次百度爬蟲耗時問題經歷

後端日誌

拿到問題,第一反應就是讓後端的同學查下日誌,看是不是真的出現300+s的情況,
但實際查詢後發現,並沒有出現這種情況,後端的日誌顯示介面返回都很快,基本是ms級別,秒都談不上,更何況300s?

既然後端沒有問題,那就肯定是前端了;

JB的測試之旅-記一次百度爬蟲耗時問題經歷

前端

既然懷疑是前端問題,那我們就嘗試重現下吧,直接用Chrome按F12進入開發者模式,
直接重新整理試試,手動重複幾十次,基本都是2這個區間內,而且首頁資源特別多,如果首頁都沒問題,其他頁面就更不會有問題了;

JB的測試之旅-記一次百度爬蟲耗時問題經歷

(手動重試中) 突然會發現一次耗時比較久的,長達10s,看了下時間的佔比,如下:

JB的測試之旅-記一次百度爬蟲耗時問題經歷

咦,一個圖片用了3s?什麼鬼?
而且會發現,有些圖片size會高達4M?

瞬間把苗頭之前了資源這塊,為了驗證我們的想法,使用了webpagetest(文末會簡單介紹)工具來驗證下網頁的耗時,這個工具是個網頁,直接開啟輸入需要測試的網址即可;

先來一次結果

JB的測試之旅-記一次百度爬蟲耗時問題經歷

直接看頂部的截圖,嚶嚶嚶,fully loaded time居然去到16S了,這肯定有問題,接著繼續看:

JB的測試之旅-記一次百度爬蟲耗時問題經歷

嘖嘖嘖,一個圖片的下載用了8S,這效能不太行啊,而且有些圖片的size的確很大,所以第一反應是,圖片壓縮,減少size,另外,網站本身會偶爾出現404,這塊本身就會影響到seo的收錄已經爬取,在這種情況,不得不懷疑任何一切相關的,因此就擼起袖子開始幹了:

1)資源壓縮,部分業務邏輯合併,減少請求數量,快取機制
2)出現404的原因是,當初設計時,如果眾多介面裡某一介面異常,前端直接判定偉404,因此把這塊邏輯修改下,介面異常不會導致前端跳404,最多是資料不展示;

開發、測試、上線、絕望,一潑冷水澆下來,大家都痿了;
幾個臭皮匠一起討論了半天,也沒個結論,此時,部分同學覺得這是個吃力不討好的工作,慢慢的開始淡出這個工作了,有點所謂的選擇性失盲了;

JB的測試之旅-記一次百度爬蟲耗時問題經歷

再次分析

即使運營老大、老闆天天問,但是依然沒有任何進展,這問題,就這麼坑爹?

此時,某拍黃片同學(php)主動(被迫)出來跟進這個問題;

啪啪啪好幾天過去了,突然某一天,釘釘群了,該拍黃片同學給出一個方向,這個問題有初步懷疑點了,那就是伺服器頻寬問題導致的,解決方案就是臨時擴充套件頻寬;

JB的測試之旅-記一次百度爬蟲耗時問題經歷

怎麼分析的?

既然能給出這樣的結論,肯定是有資料支撐他的,那我們就來看看,是什麼支撐他這個結論;

依舊是先分析後臺日誌,過濾百度過來的請求,某一條有40幾個,然後再根據介面響應超過10S的方式進行過來,發現剩下2條日誌:

JB的測試之旅-記一次百度爬蟲耗時問題經歷
從日誌上看,基本耗時都在18S,也讀是百度爬蟲那過來的;

既然都有日誌了,那就模擬下看看是不是真要那麼久,這裡的模擬爬蟲用的是百度熊掌號自帶的工具:

JB的測試之旅-記一次百度爬蟲耗時問題經歷

輸入出現問題的地址,結果如下:

JB的測試之旅-記一次百度爬蟲耗時問題經歷
只需要關注最下面的下載時長:0.166s,重複多幾次,依然如此

這個後臺的日誌不一樣,那就說明,這個問題不是必現的,而且有特定場景導致的;

從後臺的日誌上看,剛爬了幾次的日誌,也的確跟百度上顯示的類似,那說明百度上的時長是可信的:

JB的測試之旅-記一次百度爬蟲耗時問題經歷
從上圖可看出,最大一次也不超過3S,與一開始反饋的300S相差甚遠;

此時再去分析伺服器的情況:

JB的測試之旅-記一次百度爬蟲耗時問題經歷

伺服器是5M的頻寬,從日誌上看,的確有部分時間段是超過了5M,而且出現爬取比較慢的時間剛好對的上伺服器超過5M的時間;

因此該同學才敢說,懷疑是因為頻寬,雖然聽上去有點巧合,但是在百般無策的情況下,只能相信是這種巧合了;

然後就調整頻寬,觀察幾天,畢竟爬蟲這種東西是靠別人的,心急不來,在等待的期間,做了3件事:

1) 資料查詢借鑑
導致抓取時間達到幾十萬的情況
1) 抓取該頁面的時候部分圖片無法抓取到;
2) 連結超時;
3) 百度內部調整導致;

從結果看,個人傾向1、2可能性大;

2)跟前端同學溝通下,後端返回的18S,是怎樣的標準?
回到文章頂部,有提及到這個網站架構是node+nginx+php,那這18S,
按照理解,應該就是Php返回到nginx的時間,那nginx到node中間傳輸會不會也有損耗,
比如跟網速有關係、伺服器效能等,都有可能有折損,然後node接收後,再渲染顯示,等渲染完成,爬蟲才認為整個過程完畢?(前面提及到,這裡預設爬蟲規則是開始請求到渲染完畢,但實際未知)

當時提到一個疑問,假如說,node或者nginx有問題了,那是不是就會出現耗時很長的情況?
但當時因為沒資料支撐,大家都覺得,嗯,有這種可能,這種想法一閃而過,但是有什麼原因導致node或者nginx有問題,真沒想到;

事實回頭看,猜對了,的確是node出問題導致

當也因為當時沒想到,後面才更好的梳理了;

3)影響網路傳輸的原因有哪些?
找到一個答案,不知道對不對,僅參考:

線上響應速度取決於當前被訪問的目的地頻寬、併發數,還有,伺服器機器當前使用時間,是否存在物理
儲存器和各運算器控制器老化情況,以及發起爬取的機器訊號傳送和接收情況;
複製程式碼

最重要的兩點就是頻寬,併發數,頻寬驗證是沒影響,那這個會跟併發數有關嗎

再次梳理

回到正文,上線幾天後發現,還是不行,依然有問題,說明頻寬不是問題點,那怎麼辦?

上面提及到,既然頻寬不是問題,那就可能跟併發數有關係了,而且爬蟲過來肯定也是併發這麼過,所以就把苗頭對準併發了;

但是在實際去看併發之前,還是把邏輯梳理了一遍:

JB的測試之旅-記一次百度爬蟲耗時問題經歷

根據上面的資訊,現在從後端nginx可以get到的是,PHP和後端處理時間非常快,基本在0.1-0.5之間;

從流程上來看,前端負責接收和返回後端的是nojs,所以有理由懷疑,異常發生的原因是在node層,結合上面的併發可能性,有可能是多併發,導致nojs程式cpu佔用負載,導致處理時間加長。

這樣也能很好地解釋,為什麼有的時候,抓取的時間只需要0.1到0.5,但是有時卻需要消耗長達20萬毫秒;

既然有所懷疑,那就開始幹吧~

實驗

本次的實驗目的很簡單,就是在高併發的環境下,進行百度爬取的行為,看看資料是不是正常;

工具的選擇,不糾結,壓測用apache ab,原因命令列,便捷,爬蟲就直接用百度自帶的;

分3組資料:
1)不使用併發,直接使用百度爬取
2)針對具體某一新聞頁進行併發,並且爬取這條新聞頁,連結
3)針對首頁(www.51hjgt.com)進行併發,爬取上面的新聞頁

併發命令:

ab -c 60 -n 100 http://www.51hjgt.com/
-n:執行請求的數量
-c:每個請求的併發連線數,理解成使用者數也可以
複製程式碼

結果發現,嘗試多次,第三種情況下終於出現了抓起失敗的情況!!撒花~

JB的測試之旅-記一次百度爬蟲耗時問題經歷

JB的測試之旅-記一次百度爬蟲耗時問題經歷

JB的測試之旅-記一次百度爬蟲耗時問題經歷

ok,雖然不是百分百能重現,但至少重現到一次了,也就說明的確有問題的;

下面是點選百度上的檢視幫助裡的內容:

JB的測試之旅-記一次百度爬蟲耗時問題經歷

Ok,拿著這個去跟前端反饋,結果前端負責人是這麼回答的:

嗯,的確有可能存在這樣的情況,原因是因為現在專案的node使用的是單程式,有可能會因併發問
題導致處理不來的情況,為什麼要用單程式,是因為運維那邊不會配置多程式導致的,這個下個版本
會處理;
複製程式碼

嗯,這個問題就這樣算是有個交代了;

小結

總結下這次遇到的問題吧;

收到問題->尋求資料如何統計->分析後端日誌->壓縮圖片size及處理404問題->再次分析,懷疑跟頻寬有關係->重新梳理流程,懷疑併發->驗證->重現問題

其實從上面的流程來說,貌似沒太多的問題,在不瞭解或者不熟悉的業務上,也只能不停的去排查來驗證假象;

但有個最大的問題是,像這類問題,理應第一時間想到併發跟頻寬,但是在這次卻是最後才想到,由此可見敏感度不夠,無論是測試還是研發,對這種問題跟進能力比較欠缺,後面需要加強這類問題的敏感度;

上面提及到的壓縮圖片size和處理404的問題,即使沒有這次的反饋,從網頁本身考慮,本身就是需要去做的事情;

apache ab介紹

對於網站而言,壓測是必須要做的工作,那壓測的工具有很多,jmeter,loadrunner,ab,那為什麼會選擇ab?
個人覺得主要的原因是邊界,命令列,windows\Linux\mac都支援使用;

下載安裝

因博主電腦是win10,所以是以windows的下載來講述,請了解;
1)開啟連結:httpd.apache.org/download.cg…
2)開啟連結後,點選紅框的Files for microsoft windows

JB的測試之旅-記一次百度爬蟲耗時問題經歷
3)開啟後,點選紅框的ApacheHaus
JB的測試之旅-記一次百度爬蟲耗時問題經歷
4)向下滑動,滑鼠點選曉紅框裡的內容,就會自動進行下載
JB的測試之旅-記一次百度爬蟲耗時問題經歷

但是試過好幾次可能是網路原因,下載很慢,而且可能會斷開,因為分析一個2.3.4.3版本的zip包,需要的同學自取:
連結:pan.baidu.com/s/1MRCmEoiU… 密碼:seag

下載完就解壓,使用Windows下的cmd命令列,去到剛解壓的目錄下的bin目錄

JB的測試之旅-記一次百度爬蟲耗時問題經歷
然後輸入ab,如果不報錯,則說明是成功了;

JB的測試之旅-記一次百度爬蟲耗時問題經歷

當然,有同學覺得每次都進來這個目錄很麻煩,那可以把Apache24\bin這個路徑配置到環境變數,後續就可以直接ab使用了,具體Windows下環境變數怎麼配置,網上搜尋下,很多的~

直接壓測網站

命令: ab -c 50 -n 50 http://www.baidu.com/
注意:網站地址,必須在後方加上"/",或指定相應檔案。
複製程式碼

執行後,就會有下圖的結果輸出:

JB的測試之旅-記一次百度爬蟲耗時問題經歷

壓測就是這麼簡單,但是要分析上圖的內容,才有價值
這一陀看不懂?沒關係,下面教你怎麼看

ab命令引數說明

第一次使用ab命令時,不知道有什麼引數,可以輸入ab -help,然後就會彈出這麼一坨東西:

JB的測試之旅-記一次百度爬蟲耗時問題經歷

一般常用的引數就下面幾個:

-n:執行請求的數量
-c:每個請求的併發連線數
-t:等待響應時間
-V:顯示版本資訊
複製程式碼

更加多詳細引數說明:

引數 全稱 描述
-A auth-username:password 對伺服器提供BASIC認證信任。 使用者名稱和密碼由一個:隔開,並以base64編碼形式傳送。 無論伺服器是否需要(即, 是否傳送了401認證需求程式碼),此字串都會被髮送。
-c concurrency 一次產生的請求個數。預設是一次一個。
-C cookie-name=value 對請求附加一個Cookie:行。 其典型形式是name=value的一個引數對。 此引數可以重複。
-d 不顯示"percentage served within XX [ms] table"的訊息(為以前的版本提供支援)。
-e csv-file 產生一個以逗號分隔的(CSV)檔案, 其中包含了處理每個相應百分比的請求所需要(從1%到100%)的相應百分比的(以微妙為單位)時間。 由於這種格式已經“二進位制化”,所以比'gnuplot'格式更有用。
-g gnuplot-file 把所有測試結果寫入一個'gnuplot'或者TSV (以Tab分隔的)檔案。 此檔案可以方便地匯入到Gnuplot, IDL, Mathematica, Igor甚至Excel中。 其中的第一行為標題。
-h 顯示使用方法。
-H custom-header 對請求附加額外的頭資訊。此引數的典型形式是一個有效的頭資訊行,其中包含了以冒號分隔的欄位和值的對 (如, "Accept-Encoding: zip/zop;8bit").
-i 執行HEAD請求,而不是GET。
-k 啟用HTTP KeepAlive功能,在一個HTTP會話中執行多個請求。 預設時,不啟用KeepAlive功能. -n requests 在測試會話中所執行的請求個數。 預設時,僅執行一個請求,但通常其結果不具有代表意義。
-p POST-file 包含了需要POST的資料的檔案.
-P proxy-auth-username:password 對一箇中轉代理提供BASIC認證信任。 使用者名稱和密碼由一個:隔開,並以base64編碼形式傳送。 無論伺服器是否需要(即, 是否傳送了401認證需求程式碼),此字串都會被髮送。
-q 如果處理的請求數大於150, ab每處理大約10%或者100個請求時,會在stderr輸出一個進度計數。 此-q標記可以抑制這些資訊。
-s 用於編譯中(ab -h會顯示相關資訊)使用了SSL的受保護的https,而不是http協議的時候。此功能是實驗性的,也是很簡陋的。最好不要用。
-S 不顯示中值和標準背離值而且在均值和中值為標準背離值的1到2倍時,也不顯示警告或出錯資訊。 預設時,會顯示 最小值/均值/最大值等數值。(為以前的版本提供支援).
-t timelimit 測試所進行的最大秒數。其內部隱含值是-n 50000。它可以使對伺服器的測試限制在一個固定的總時間以內。預設時,沒有時間限制。
-T content-type POST資料所使用的Content-type頭資訊。
-v verbosity 設定顯示資訊的詳細程度,4或更大值會顯示頭資訊,3或更大值可以顯示響應程式碼,2或更大值顯示警告和其他資訊。
-V 顯示版本號並退出。
-w 以HTML表的格式輸出結果。預設時,它是白色背景的兩列寬度的一張表。
-x (table) -attributes 設定(table)屬性的字串。 此屬性被填入(table 這裡 ).
-X proxy[:port] 對請求使用代理伺服器。
-y (tr)-attributes 設定(tr)屬性的字串.
-z (td)-attributes 設定(td)屬性的字串

例項

ab -n 3000 -c 3000 www.baidu.com/

c 100 即:每次併發3000 個
n 10000 即: 共傳送3000 個請求
複製程式碼

ab -t 60 -c 100 www.baidu.com/

在60秒內發請求,一次100個請求。
複製程式碼

帶引數的的請求

ab -t 60 -c 100 -T "application/x-www-form-urlencoded" p p.txt www.baidu.com/jb.html

p.txt 是和ab.exe在一個目錄 p.txt 中可以寫引數,如 p=wdp&fq=78 要注意編碼問題
複製程式碼

引數中的三種形式

application/x-www-form-urlencoded (預設值)
    就是設定表單傳輸的編碼,典型的post請求
multipart/form-data.
    用來指定傳輸資料的特殊型別的,主要就是我們上傳的非文字的內容,比如圖片,mp3,檔案等等
text/plain . 是純文字傳輸的意思
複製程式碼

結果分析

執行完後,會有這麼一坨東西:

JB的測試之旅-記一次百度爬蟲耗時問題經歷
下面就來講解,到底是什麼意思:

This is ApacheBench, Version 2.3
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.80.157 (be patient)
Completed 400 requests
Completed 800 requests
Completed 1200 requests
Completed 1600 requests
Completed 2000 requests
Completed 2400 requests
Completed 2800 requests
Completed 3200 requests
Completed 3600 requests
Completed 4000 requests
Finished 4000 requests

Server Software: Apache/2.2.15
#Web伺服器引擎
Server Hostname: 192.168.80.157
#伺服器地址
Server Port: 80
#伺服器埠

Document Path: /phpinfo.php
#請求的檔案路徑
Document Length: 50797 bytes
#檔案大小

Concurrency Level: 1000
#測試的併發數
Time taken for tests: 11.846 seconds
#整個測試持續的時間,測試總耗時
Complete requests: 4000
#完成的請求數量,即成功收到返回的數目
Failed requests: 0
#失敗的請求數量
Write errors: 0
Total transferred: 204586997 bytes
#整個過程中的網路傳輸量
HTML transferred: 203479961 bytes
#整個過程中的HTML內容傳輸量
Requests per second: 337.67 [#/sec] (mean)
#最重要的指標之一,相當於LR中的每秒事務數,後面括號中的mean表示這是一個平均值,即 每秒請求數,等於總請求數/測試總耗時,平均響應時間
Time per request: 2961.449 [ms] (mean)
#最重要的指標之二,相當於LR中的平均事務響應時間,後面括號中的mean表示這是一個平均值,可以理解為使用者平均請求等待時間(響應時間)
Time per request: 2.961 [ms] (mean, across all concurrent requests)
#每個連線請求實際執行時間的平均值,可以理解為伺服器平均請求等待時間(併發請求時間)
Transfer rate: 16866.07 [Kbytes/sec] received
#平均傳輸速率
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 483 1773.5 11 9052
Processing: 2 556 1459.1 255 11763
Waiting: 1 515 1459.8 220 11756
Total: 139 1039 2296.6 275 11843
#網路上消耗的時間的分解,響應時間小、中、大值

Percentage of the requests served within a certain time (ms)
50% 275
66% 298
75% 328
80% 373
90% 3260
95% 9075
98% 9267
99% 11713
100% 11843 (longest request)
#整個場景中所有請求的響應情況。在場景中每個請求都有一個響應時間,其中50%的使用者響應時間
小於275毫秒,66%的使用者響應時間小於298毫秒,最大的響應時間小於11843毫秒。對於併發請求,
cpu實際上並不是同時處理的,而是按照每個請求獲得的時間片逐個輪轉處理的,所以基本
上第一個Time per request時間約等於第二個Time per request時間乘以併發請求數。
複製程式碼

使用ab常見的問題

1)ab命令在一般系統上面做測試時候,一般併發不能超過1024個,其實是因為因為系統限制每個程式開啟的最大檔案數為1024,可以用ulimit -a來檢視
2)-n 可以指定最大請求數,但是不能超過50000個
3)-v n 當n>=2 時,可以顯示傳送的http請求頭,和響應的http頭及內容,壓力測試時不要這麼做
4)在做壓力測試的時候,一般情況下壓力測試客戶端接收到的資料量一定會遠大於傳送出去的資料量
5)帶引數的壓力測試示例,ab 'www.baidu.com/?a=1&b=…'
6)使用的時候,出現這個提示,The timeout specified has expired (70007),
原因是超時了,可以增加 -k (keep的意思)引數,保持連線進行測試;

JB的測試之旅-記一次百度爬蟲耗時問題經歷

解決方案:

ab -c 50 -n 100 -k http://www.51hjgt.com/
複製程式碼

大概就這樣吧,謝謝大家~

JB的測試之旅-記一次百度爬蟲耗時問題經歷

相關文章