| date : 2017.3.7 |linux
apache 提供的common-httpclient (3.1 的版本),在調用httpclient的時候,是很方便的,在實際的項目中,調用第三方服務,也常常使用;此次在客戶現場發現了一個問題;apache
咱們調用第三方的服務,第三方服務在監控鏈接的時候,提到咱們發起的鏈接有許多的close_wait鏈接;網絡
原來是懷疑鏈接沒有釋放;檢查了代碼,是有調用了 releaseConnection的方法;沒細看,看這個方法名,就是關閉鏈接了;有點怪異;併發
繼續查下去;作了一個測試;目前使用httpclient的方法大體以下:框架
private void doHttpTest(){ HttpClient httpClient = new HttpClient(); GetMethod get = new GetMethod("http://www.baidu.com"); try{ httpClient.executeMethod(get); } catch (Exception err){ } finally { get.releaseConnection(); } } @Test public void do100Test(){ for(int i=0 ;i<100;i++){ this.doHttpTest(); } System.out.print("111"); }
該方法在自測時候,在最後一個 System.out.print
方法打了斷點;(知道爲啥要留這個方法了吧,打斷點用的。。哈哈哈) debug , 以後,檢查了該進程發起的鏈接; 先看看 www.baidu.com的IP 吧;源碼分析
JPS看看,咱的進程ID測試
來吧,檢查一下進程 windons 下面的命令:netstat -ano|find "20168" |find "61."
計數命令:netstat -ano|find "20168" |find "61." /c
this
100個鏈接哦,,還都是 CLOSE_WAIT的; 好吧;就說明咱們上面腳本中循環了100個,就壓根沒有是否端口呀。。。.net
爲啥,,這個是爲啥。已經調用了 releaseConnection() ;難道是releaseConnection()的問題,要不看看的唄。 GetMethod --> HttpMethodBase --> HttpConnection --> HttpConnectionManager 好吧,這裏是個接口。咋整,從 HttpClient入口,發現默認是使用 SimpleHttpConnectionManager ,走起; 源碼以下:
看到了,坑的地方來了;
if(this.alwaysClose)
這個值,默認是false的哦。。並且,貌似還沒地方賦值的呢。。換句話說,默認是 finishLastResponse,查看這個方法,臥槽,厲害了,只是清理了 inputStream 呢。但鏈接木有關閉啊; 要關閉鏈接怎麼辦?咱們本身來關閉?往下翻了翻,額,有個closeIdleConnections 的方法;這個的源碼看了一下,額,關閉在Nms以前的鏈接呢。。恩。這個能夠用; 試試看;debug
新的測試代碼以下:就補充了closeIdleConnections的內容;
private void doHttpTest(){ HttpClient httpClient = new HttpClient(); GetMethod get = new GetMethod("http://www.baidu.com"); try{ httpClient.executeMethod(get); } catch (Exception err){ } finally { get.releaseConnection(); //就加了這裏哈。。 httpClient.getHttpConnectionManager().closeIdleConnections(0L); } } @Test public void do100Test(){ for(int i=0 ;i<100;i++){ this.doHttpTest(); } System.out.print("111"); }
同以上的測試過程,檢查鏈接數:
搞定,木有對 www.baidu.com 的鏈接了;;很好,鏈接都關閉了。
鏈接的關閉,要補上 closeIdleConnections 的調用;或者是直接對 connection.close 的方法。 那麼爲何 apache 的 common-httpclient不直接關閉呢。實際上,這個是基於效率的考慮,在網絡鏈接的時候, http鏈接的建立是耗時的,而框架是但願同一個connection能夠複用的。但咱們在使用的時候,每次都 new HttpClient 的方式,也就致使了複用不了;在這個狀況下,仍是乾脆關閉吧;
若是併發太高,不進行關閉的話,應用會linux下運行會出現 too many open files 的錯誤。。
另外:考慮升級了,升級到 httpcomponents 的 httpclient
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.3</version> </dependency>