我手頭有個java web專案。 由于業務上一些要求,必須對外提供介面,內部又是通過調一個第三方的服務滿足需求,總的來說就是個中轉查詢吧,當然可以從我這個專案查看下日志,方便統計之類的。
但問題來了。 這個第三方服務因為種種原因,有幾個慢介面,經常超過1s,有時候甚至幾秒才會回傳。 上線后已經發生過幾次事故了,原因都是客戶端大量請求到我這個服務,再透傳過去,因為回傳太慢,我這邊fd耗盡,導致假死,行程雖然還在,但是請求根本進不去了。 出問題的時候,查看網路連接,CLOSE_WAIT高達幾萬。只有重啟應用搶救。 但這是個不定時炸彈,誰也不知道哪天有掛了。
目前用的網路工具類就是老專案拷過來的基于HttpClient封裝的,正常請求完后也會主動close掉釋放資源。 出過幾次事故后,每次都把超時時間設短一點。 最初是10秒,現在已經改成3秒了。
但感覺這樣始終治標不治本。 如果三方介面真的慢了,哪怕是成功的請求每個都阻塞幾秒,客戶端請求如果增大,也會導致linux系統句柄耗盡吧。 有什么好的解決方案么? 能夠替代HttpClient呼叫?
uj5u.com熱心網友回復:
是否可以把用的HttpClient工具類和使用工具類隱去業務資訊的代碼貼出來一下,猜測是HttpClient未正確釋放連接導致linux服務器FD耗盡uj5u.com熱心網友回復:
還有HttpClient版本說下uj5u.com熱心網友回復:
1.如果對方呼叫介面采取的是迭代呼叫模式,你方提供批量介面,這樣可以將對方的多次請求變為由自己控制訪問第三方介面了。好處是自己完全可控,自己可以對這堆資料根據實際情況一個個呼叫或者分成小批次多執行緒呼叫。2.加機器,分布式部署。
3.異步回呼模式,這個只是一個思路,符不符合你們的業務不清楚。
uj5u.com熱心網友回復:
還有不知道你們 httpclient 怎么用的啊,加沒加連接池啊uj5u.com熱心網友回復:
我們目前用的HttpClient包 版本是4.5.5。 主要用的封裝的方法是這樣的(也是從別的專案copy過來用的)
public static String postJsonStrForBusData(String url, String jsonParam) {
LOGGER.info("請求url:"+url+",請求引數:"+jsonParam);
CloseableHttpResponse response = null;
HttpPost httpPost = null;
CloseableHttpClient httpClient =null;
try {
httpClient = HttpClients.custom().disableAutomaticRetries().build();
httpPost = new HttpPost(url);
//設定超時間
httpPost.setConfig(***設超時時間,這里略去***);
StringEntity entity = new StringEntity(jsonParam, "utf-8");
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
response = httpClient.execute(httpPost);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
httpPost.abort();
LOGGER.error("HttpClient,error status code :" + statusCode);
return null;
}
HttpEntity resultEntity = response.getEntity();
String result = null;
if (resultEntity != null) {
result = EntityUtils.toString(resultEntity, "utf-8");
}
EntityUtils.consume(resultEntity);
return result;
} catch (Exception e) {
LOGGER.error("HttpClient,error status code :" + e.getMessage());
} finally {
if (httpPost != null) {
httpPost.releaseConnection();
}
if(httpClient!=null){
try {
httpClient.close();
} catch (IOException e) {
LOGGER.error("httpClient-IOException",e);
}
}
}
return null;
}
uj5u.com熱心網友回復:
我看了下代碼中 EntityUtils.consume() httpClient.close() 的原始碼,會正確關閉連接,我之前的猜測是錯誤的.uj5u.com熱心網友回復:
我在golang也遇到過這個問題,http client需要用連接池和長連接,總之就是需要連接的可重復使用性。如果是在高并發時大量的短連接不斷的開關,就會導致很多的連接處于CLOSE_WAIT狀態,這個狀態會持續約4分鐘,會導致fd資源耗盡。
uj5u.com熱心網友回復:
需要配置HttpClient連接池PoolingHttpClientConnectionManager,設定最大連接數,防止機器資源耗盡崩潰,如果最大連接數不滿足現有業務就需要考慮加機器了,負載均衡uj5u.com熱心網友回復:
如果連接資源很緊缺(慢查詢介面),那么可能你需要加一層快取層。用MQ做一層快取。這樣哪怕你的請求來的很多,排排隊,在連接池有資源的時候處理請求uj5u.com熱心網友回復:
這個貼子 推薦的blog有一個很值得借鑒https://blog.csdn.net/ciyiwa8779/article/details/100291067?utm_medium=distribute.pc_relevant_bbs_down.none-task-blog-baidujs-1.nonecase&depth_1-utm_source=distribute.pc_relevant_bbs_down.none-task-blog-baidujs-1.nonecase
uj5u.com熱心網友回復:
這篇博客也值得一看轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/22635.html
標籤:Web 開發
上一篇:spring boot2 與hibernate5 org.postgresql.util.PSQLException: 錯誤: 關系 "表" 已經存在
下一篇:Error:(4, 26) java: 程式包net.sf.cglib.proxy不存在,為啥找不到這個依賴,十分不解
