二月份的工作總結(jié),分享一下胯盯。
近期我們線(xiàn)上A網(wǎng)站爬取效率不高懈费,時(shí)間比較長(zhǎng)计露,由于元旦時(shí)可以達(dá)到30w+一天,故排查重點(diǎn)還是流程以及dubbo線(xiàn)程池問(wèn)題憎乙。
1票罐、dubbo線(xiàn)程池發(fā)生:RejectedExecutionException: Thread pool is EXHAUSTED!異常時(shí),使用jstat查看jvm使用情況泞边,GCT的時(shí)間在2-3之間该押,不算太高。
2阵谚、使用jstack查看堆棧信息蚕礼,發(fā)現(xiàn)大量java.lang.Thread.State: RUNNABLE烟具,沒(méi)有死鎖發(fā)生。對(duì)比A網(wǎng)站和B網(wǎng)站的堆棧信息奠蹬,A網(wǎng)站java.lang.Thread.State: RUNNABLE比例大概是85%以上朝聋,其余是TIMED_WAITING和WAITING;而B(niǎo)網(wǎng)站java.lang.Thread.State: RUNNABLE比例大概是10%~20%囤躁,其余是TIMED_WAITING和WAITING冀痕。(事后分析,這里已經(jīng)有問(wèn)題了狸演,大部分的任務(wù)都是RUNNABLE應(yīng)該是存在問(wèn)題的)
3言蛇、網(wǎng)上查找關(guān)于查看dubbo線(xiàn)程池方法。
發(fā)現(xiàn)可以使用telnet命令來(lái)查看dubbo線(xiàn)程池(http://alibaba.github.io/dubbo-doc-static/Telnet+Command+Reference-zh-showComments=true&showCommentArea=true.htm)
如圖所示:
可以查看線(xiàn)程池的健康程度宵距、最大線(xiàn)程數(shù)腊尚、活躍線(xiàn)程數(shù)、任務(wù)數(shù)等等消玄。
發(fā)現(xiàn)當(dāng)A網(wǎng)站的線(xiàn)程池active是一直波浪增長(zhǎng)的,直至達(dá)到max翩瓜,即線(xiàn)程池滿(mǎn)了受扳。但查看爬蟲(chóng)自服務(wù)、B網(wǎng)站等兔跌,active數(shù)基本都是1,會(huì)增長(zhǎng)也會(huì)落下來(lái)华望。
至此,基本上可以判斷A網(wǎng)站效率問(wèn)題是由于某種原因?qū)е禄钴S線(xiàn)程數(shù)無(wú)法釋放,導(dǎo)致最終線(xiàn)程池卡死石洗。
4紧显、由于A網(wǎng)站爬蟲(chóng)有四個(gè)定時(shí)器啟動(dòng)涉兽,分別是a功能、b功能丹允、c功能、d功能,所以分開(kāi)試驗(yàn)前塔,只啟動(dòng)單個(gè)定時(shí)器华弓,看active數(shù)據(jù)是否增長(zhǎng)。
a吱抚、啟動(dòng)a功能定時(shí)器昌粤,不增長(zhǎng)鸵膏;
b膊升、啟動(dòng)b功能定時(shí)器,緩慢增長(zhǎng)非区;
c征绸、啟動(dòng)c功能定時(shí)器,增長(zhǎng)較快祝拯;
d佳头、啟動(dòng)d功能定時(shí)器凄鼻,不增長(zhǎng)膘格。
對(duì)比代碼纱控,發(fā)現(xiàn)b、c中均包含httpClient調(diào)用,問(wèn)題出在httpClient調(diào)用鲫售。
5、由于B網(wǎng)站也使用了httpClient調(diào)用匀哄,但并沒(méi)有出現(xiàn)問(wèn)題贡耽,故需要測(cè)試使用代理IP和不使用代理IP兩種蒲赂。
寫(xiě)測(cè)試代碼測(cè)試httpClient調(diào)用時(shí)使用代理IP與不使用代理IP,發(fā)現(xiàn)訪(fǎng)問(wèn)B網(wǎng)站、百度等網(wǎng)站,不使用代理IP卧土,active不增長(zhǎng);使用代理IP訪(fǎng)問(wèn)裁判文書(shū)則active增長(zhǎng)媳谁。懷疑httpClient有些操作導(dǎo)致了線(xiàn)程池資源耗盡。(事后發(fā)現(xiàn)此處可以不測(cè)試鸭叙,因?yàn)锳網(wǎng)站與B網(wǎng)站除了使用與與不使用代理IP外沈贝,最大的區(qū)別是B網(wǎng)站幾乎不超時(shí),而A網(wǎng)站大概率超時(shí))
6罩引、網(wǎng)上查找原因徙融,看了http://blog.csdn.net/clementad/article/details/75649625 這篇文章后發(fā)現(xiàn)httpClient的超時(shí)設(shè)置少了一個(gè),應(yīng)該增加如下所示:
運(yùn)行代碼后發(fā)現(xiàn)索然active還是有些增長(zhǎng),但明顯慢了很多龙助,在家里運(yùn)行了將近3個(gè)小時(shí)胸哥,從最開(kāi)始漲到了50左右,然后基本穩(wěn)定
7赋朦、我一個(gè)同事后來(lái)發(fā)現(xiàn)timeout時(shí)間設(shè)置沒(méi)有生效宠哄,在httpClient.execute()之前纹因,需要設(shè)置配置生效,httpget.setConfig(requestConfig);這樣設(shè)置后琳拨,運(yùn)行一晚上瞭恰,active數(shù)穩(wěn)定在20左右。后來(lái)發(fā)現(xiàn)是由于setDefaultRequestConfig兩次狱庇,第二次set時(shí)可能是沖掉了第一次的timeout設(shè)置惊畏。之所以配置clientBuilder.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(30000).build()); 也能夠達(dá)到效果鹊奖,但效果不如使用httpget.setConfig(requestConfig);設(shè)置效果明顯司训,是因?yàn)榍罢呦喈?dāng)于給httpClient設(shè)置了一個(gè)超時(shí)時(shí)間的設(shè)置,會(huì)起效果走贪,但也只是給響應(yīng)設(shè)置了超時(shí)時(shí)間浪讳,而缺少下面三個(gè)配置缰盏,則效果不夠理想
//客戶(hù)端和服務(wù)器建立連接的timeout
requestConfigBuilder.setConnectTimeout(30000);
//從連接池獲取連接的timeout
requestConfigBuilder.setConnectionRequestTimeout(30000);
//連接建立后,request沒(méi)有回應(yīng)的timeout
requestConfigBuilder.setSocketTimeout(30000);
8淹遵、測(cè)試環(huán)境和最終的線(xiàn)上環(huán)境口猜,同時(shí)配置了四個(gè)超時(shí)時(shí)間且都是生效的,這樣透揣,長(zhǎng)期運(yùn)行下active數(shù)量峰值可達(dá)到100以上济炎,但會(huì)回落,可以回落到個(gè)位數(shù)十位數(shù)辐真,比較穩(wěn)定须尚。
9崖堤、dubbo線(xiàn)程池穩(wěn)定后,A網(wǎng)站爬取的效率則得到了提升耐床,目前速度比較穩(wěn)定密幔,需要長(zhǎng)期觀(guān)察爬取速度和dubbo線(xiàn)程池active數(shù)量。