轉自:http://luan.iteye.com/blog/1820054
I/O exception (java.net.SocketException) caught when processing request: Connect
查閱了HttpClient官方的異常說明文檔(http://hc.apache.org/httpclient-3.x/exception-handling.html),可以看到以下一段話:
In some circumstances, usually when under heavy load, the web server may be able to receive requests but unable to process them. A lack of sufficient resources like worker threads is a good example. This may cause the server to drop the connection to the client without giving any response. HttpClient throws NoHttpResponseException when it encounters such a condition. In most cases it is safe to retry a method that failed with NoHttpResponseException.
在某些情況下,通常在重負載下時,Web服務器可能能夠接收請求,但無法處理它們。缺乏足夠的資源,比如工作線程,這可能會導致服務器斷開連接的客戶端沒有給予任何回應。當它遇到這樣的條件HttpClient會拋出NoHttpResponseException。此異常是由於服務器端過載而拒絕接受請求(不再響應)所致。
老外有一篇文章,很好的描述了類似代碼的性能隱患:《HttpClient容易忽視的細節——連接關閉》
1、英文原文:http://www.codeweblog.com/httpclient-s-easy-to-overlook-the-details-the-connection-is-closed/
2,中文翻譯:http://www.iteye.com/topic/234759
總述:實現一個HTTP接口不是件困難的事情,但是如何讓這樣的HTTP接口在高壓力下(短時間內大數據量)也有穩定良好的表現,則不僅僅是HTTP服務器端需要做好設計與優化,而且HTTP客戶端方面也同樣需要非常謹慎與注意一些代碼細節。否則,很有可能因(雙方或單方)代碼或配置中存在性能隱患,在軟硬件環境的配合下就會出現一些“靈異”故障。
【HTTP協議知識
為便於讀者理解后文,先簡述一些與HTTP性能密切相關的、又常常被工程師們所不深究的HTTP協議基礎知識。
一,什么是HTTP KeepAliv 電子郵件
HTTP KeepAlive是就是通常所稱的長連接。KeepAlive即服務器端為同一客戶端保持連接一段時間(不立即關閉),以便於更多來自於此客戶端的后續請求不斷的利用此連接直至連接超時。
在HTTP1.0和HTTP1.1協議中都有對的KeepAlive的支持。其中HTTP1.0需要在請求頭中增加“連接:保持活動”才能夠支持,而HTTP1.1默認支持。
該屬性的更多闡述:
1,下一個請求是在完成之前請求的響應被客戶端接收的情況下才發出。因此需要在向客戶端寫完之前的請求的響應后才能觸發。
2、HTTP協議是基於TCP協議的,故服務器端與客戶端都有可能關閉連接。KeepAlive只是表明了服務器端面對連接的一種優化策略,而客戶端也完全可以主動關閉之(不利用)。
二,KEEPALIVE的好處與壞處
KeepAlive帶來的好處是可以減少HTTP連接的開銷,提高性能。比如,同一頁面中如有很多內嵌的圖片、JS、CSS等請求,則可以利用此特新性,使用少量的連接數(IE下一般是2個)更快的下載下來,使得網頁更快的展示出來。
QeepAlive的壞處是:
如果有大量不同的客戶端同時(或瞬間)請求服務器端,且每一個客戶端的都長期占用連接(比如:不關閉且ConnectionTimeOut設置過長)或服務器端也不快速失效連接(KeepAliveTimeout參數設置過大)的話,可能會快速占滿服務器連接資源,導致更多的請求被排隊或被拒絕或服務器down掉。
總結:瀏覽器作為一種HTTP客戶端,充分的、很好的利用了HTTP協議的KeepAlive,讓我們的瀏覽更加快速;而我們自寫的HTTP客戶端程序在KeepAlive特性(服務器已開啟)下,需要以高數據量訪問一個HTTP接口的時候,每一次請求應當盡快關閉連接釋放資源(重點推薦)或者在同一連接上適當多發幾次請求(不推薦)。
【高性能HTTP應用的策略】
所以,當我們需要一個高性能的HTTP接口型應用時:
1,服務器端:關閉KeepAlive功能。
2、服務器端:最好直接支持HTTP協議(注意用POST,不要GET),而不是任何包裝過的協議,比如:hessian/soap等。
3、服務器端:在一個請求中,最好設計成:支持多條指令批處理,以節省連接數。
4、服務器端:對請求的處理應當盡可能的快(如在150ms內)。
5、客戶端:在代碼中,同一個客戶端實例中全部請求結束后應主動關閉連接(無須事先設置客戶端的ConnectionTimeOut參數)。
6、客戶端:如服務器未關閉KeepAlive,在同一個客戶端實例中可以適量發出多個請求(總時間應稍小於服務器KeepAliveTimeout參數)。此方式需要精確操作,不推薦。
最后,在接口設計上,對於一些異步操作,盡量不要設計成單方面輪詢模式(減少大量無謂請求數),應設計成被調用方的異步結果回調模式。
【一些優化細節】
在服務器端,我們一般選用的是Apache+Tomcat/JBoss的組合。關於JBoss的配置及優化可參看JBoss官網。
最主要的是關於Apache的優化,推薦閱讀兩篇文章:
1、Apache性能優化:http://www.aliwo.net:8080/2009/12/apache/
2,保持活動的Apache配置中的合理使用:http://www.net527.cn/a/caozuoxitong/Linux/5283.html
在客戶端的Java代碼中,我們最常使用的是HttpClient工具包。
有一些細節要注意:
1、在每一個HttpClient實例發完請求后,(如不再使用)應及時關閉連接。
最簡單的方式是,在HTTP請求頭中發送(連接:CLOSE ),指示服務器關閉當前連接。
代碼如下:
method.setRequestHeader(“Connectio “,”關閉“);//改了這個,發現性能很差
2、可以設計為單例模式:無需每次創建HttpClient實例,可多次發送請求(請求頭設置見第一條