httpclient超時總結(轉)


Httpclient超時

背景:

網站這邊多次因為httpclient調用超時時間沒設置好導致關掉,影響非常不好,而且問題重復出現,查看網絡,沒有比較明確介紹httpclient所有超時相關的設置(大部分只提到連接超時(connectintimeout),讀超時(sockettimeout),對連接池超時提到的比較少),因此本文對超時這塊最介紹,其他功能性內容,apache官方提供了比較詳細的解析,這里不做討論。具體可見:http://hc.apache.org/httpcomponents-client-ga/tutorial/html/index.html

網站這邊用的是:

<dependency>
   <groupId>commons-httpclient</groupId>  
   <artifactId>commons-httpclient</artifactId>
   <version>3.1</version>
</dependency>

 

配置:

private final static MultiThreadedHttpConnectionManager manager=new MultiThreadedHttpConnectionManager();
private final static HttpClient httpclient=new HttpClient(manager);
httpclient.setConnectionTimeout(1000);
httpclient.setTimeout(1000);

 

 

 

 

現象:

頁面無法打開,堆棧信息如下:

Name: trhead-142

State: WAITING onorg.apache.commons.httpclient.MultiThreadedHttpConnectionManager$ConnectionPool@69a4cb

Total blocked: 0 Total waited: 1

 

Stack trace:

java.lang.Object.wait(Native Method)
org.apache.commons.httpclient.MultiThreadedHttpConnectionManager.doGetConnection(MultiThreadedHttpConnectionManager.java:518)
org.apache.commons.httpclient.MultiThreadedHttpConnectionManager.getConnectionWithTimeout(MultiThreadedHttpConnectionManager.java:416)
org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:153)
org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
com.madding.test.MyRunnable.run(MyTest1.java:53)
java.lang.Thread.run(Thread.java:619)

大部分線程等待在:org.apache.commons.httpclient.MultiThreadedHttpConnectionManager.doGetConnection

 

 

分析:

問題:很明顯連接池超時沒設置,導致請求在線程池中等待,進而引起dubb無法處理其他請求。

解決:加httpclient.setHttpConnectionFactoryTimeout(1000);,設置連接池超時。

說明:廢棄方法盡量不要用

進一步分析:

為什么沒設置這個會導致請求等待:

MultiThreadedHttpConnectionManager代碼在獲取連接時去連接池取,而連接池在沒設置超時timeToWait為0,即一直處於等待狀態,如果沒有notify不會結束等待。

<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpclient</artifactId>
  <version>4.2</version>
</dependency>

 

 

 

發現代碼中即使不設置線程池超時,在高並發下也能正常訪問,查看代碼,發現是因為在默認沒設置線程池超時時把連接超時的時間作為線程超時時間,代碼如下:

 

 

而且httpclient4的代碼結構相對3做了很大重構,且實現比較優雅,可以考慮在本地私服把4.x版本添加進來。

 

完整的超時可參考如下:

staticPoolingClientConnectionManagerconnectionManager=null;

staticHttpClienthttpclient =null;

 

static{

connectionManager=newPoolingClientConnectionManager();

connectionManager.setMaxTotal(1);

httpclient=newDefaultHttpClient(connectionManager);

httpclient.getParams().setParameter("http.socket.timeout",1000);

httpclient.getParams().setParameter("http.connection.timeout",1000);

httpclient.getParams().setParameter("http.connection-manager.timeout",100000000L);

}

 

 

 

具體測試代碼如下:

3.1:

packagecom.madding.test;

 

importorg.apache.commons.httpclient.DefaultMethodRetryHandler;

importorg.apache.commons.httpclient.HttpClient;

importorg.apache.commons.httpclient.HttpStatus;

importorg.apache.commons.httpclient.MultiThreadedHttpConnectionManager;

importorg.apache.commons.httpclient.methods.GetMethod;

 

/**

*@author madding.lip

*/

publicclassMyHttpClientTest3_1 {

 

privatefinalstaticMultiThreadedHttpConnectionManagermanager=newMultiThreadedHttpConnectionManager();

privatefinalstaticHttpClienthttpclient=newHttpClient(manager);

 

publicstaticvoidmain(String[] args) {

httpclient.getParams().setParameter("http.socket.timeout",1000);

httpclient.getParams().setParameter("http.connection.timeout",1000);

httpclient.getParams().setParameter("http.connection-manager.timeout",60*60L);

// httpclient.setConnectionTimeout(1000);

// httpclient.setTimeout(1000);

// httpclient.setHttpConnectionFactoryTimeout(1000);

 

for(inti = 0; true;i++) {

newThread(newMyRunnable(httpclient),"trhead-"+ i).start();

try{

Thread.sleep(100);

}catch(InterruptedException e) {

}

}

}

 

}

 

classMyRunnableimplementsRunnable {

 

HttpClienthttpclient=null;

 

MyRunnable(HttpClient client){

httpclient= client;

}

 

publicvoidrun() {

GetMethod getMethod =newGetMethod("http://www.apache.org/");

 

try{

DefaultMethodRetryHandlerretryHandler = newDefaultMethodRetryHandler();

retryHandler.setRetryCount(0);

getMethod.setMethodRetryHandler(retryHandler);

 

 

intstatusCode =httpclient.executeMethod(getMethod);

if(statusCode == HttpStatus.SC_OK){

getMethod.getResponseBodyAsString();

}

}catch(Exception e) {

System.err.println(e);

}finally{

getMethod.releaseConnection();

}

}

}

 

 

4.2:

packagecom.madding.test;

 

importjava.io.IOException;

 

importorg.apache.http.HttpEntity;

importorg.apache.http.HttpResponse;

importorg.apache.http.client.ClientProtocolException;

importorg.apache.http.client.HttpClient;

importorg.apache.http.client.methods.HttpGet;

importorg.apache.http.client.methods.HttpUriRequest;

importorg.apache.http.impl.client.DefaultHttpClient;

importorg.apache.http.impl.conn.PoolingClientConnectionManager;

importorg.apache.http.util.EntityUtils;

 

/**

*@author madding.lip

*/

publicclassMyHttpClientTest4_2 {

staticPoolingClientConnectionManagerconnectionManager=null;

staticHttpClienthttpclient =null;

 

static{

connectionManager=newPoolingClientConnectionManager();

connectionManager.setMaxTotal(1);

httpclient=newDefaultHttpClient(connectionManager);

httpclient.getParams().setParameter("http.socket.timeout",1000);

httpclient.getParams().setParameter("http.connection.timeout",1000);

httpclient.getParams().setParameter("http.connection-manager.timeout",100000000L);

}

 

publicstaticvoidmain(String[] args) {

 

for(inti = 0; true;i++) {

newThread(newMyTest(httpclient),"trhead-"+ i).start();

try{

Thread.sleep(100);

}catch(InterruptedException e) {

}

}

}

}

 

classMyTestimplementsRunnable {

staticHttpClienthttpclient =null;

 

publicMyTest(HttpClient hc){

httpclient= hc;

}

 

publicvoidrun() {

HttpUriRequest httpget =newHttpGet("http://www.apache.org/");

try{

HttpResponse response =httpclient.execute(httpget);

 

HttpEntity entity =response.getEntity();

 

System.out.println("----------------------------------------");

System.out.println(response.getStatusLine());

if(entity !=null){

System.out.println("Responsecontent length: " +entity.getContentLength());

EntityUtils.toString(entity);

//System.out.println(EntityUtils.toString(entity));

}

System.out.println("----------------------------------------");

 

}catch(ClientProtocolException e) {

System.err.println(e);

}catch(IOException e) {

System.err.println(e);

}finally{

if(httpget !=null){

httpget.abort();

}

}

}

 

}

http://blog.csdn.net/madding/article/details/7638807

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM