httpclient請求接口超時問題

最近線上出現一個問題,外部請求過來後一直沒有響應給調用方,看日誌沒有報錯,可以復現。
想到的就可能是五個原因:

  1. 日誌文件過大導致磁盤空間滿了,導致正常的業務日誌無法寫入,但是重啓後發現日誌能正常寫入,排除這個問題
  2. 系統對接很多外部數據源,可能哪個數據源響應延遲導致沒有返回導致系統服務一直等待
  3. 數據庫連接池無可用連接,請求一直在等待可用數據庫連接導致外部數據請求一直沒有返回
  4. 代碼哪裏有問題導致死鎖,兩個線程相互等待導致系統響應異常
  5. 服務器內存溢出導致請求無返回

排查思路由易到難:
針對可能的原因2,項目重啓後看日誌發現數據庫有返回,但是仍然無響應,排除數據庫連接問題。
想到如果是原因4或者5的話,日誌裏面應該有死鎖堆棧信息或者內存溢出的異常信息,又這種問題不易排查解決,暫時擱置,看看原因2
針對外部請求的httputil工具類如下:

public class HttpUtil {
	
	 private static Logger logger= LoggerFactory.getLogger(HttpUtil.class);
	 
	public static String postJson(String url, String body) throws Exception {
		return post(url, body, "application/json");
	}

	public static String postForm(String url, String body) throws Exception {
		return post(url, body, "application/x-www-form-urlencoded");
	}

	public static String post(String url, String body, String contentType) throws Exception {
		CloseableHttpClient httpClient = HttpClients.createDefault();
		HttpPost httpPost = new HttpPost(url);
		httpPost.addHeader("Content-Type", contentType);
		httpPost.setEntity(new StringEntity(body, Charset.forName("UTF-8")));

		CloseableHttpResponse response = httpClient.execute(httpPost);
		HttpEntity entity = response.getEntity();
		String responseContent = EntityUtils.toString(entity, "UTF-8");

		response.close();
		httpClient.close();
		return responseContent;
	}
}

乍一看不覺得有啥問題,很正常的http請求,突然想到那麼針對http請求的超時時間,處理時間之類的配置是在哪裏設置的呢?這個默認配置是什麼呢?
跟蹤代碼
在這裏插入圖片描述
這邊用了設計模式的建造者模式,這個方法體很長,就不全貼出來了,具體可自己debug查看,這裏貼出關鍵內容
在這裏插入圖片描述

 public CloseableHttpClient build() {
        PublicSuffixMatcher publicSuffixMatcherCopy = this.publicSuffixMatcher;
        if (publicSuffixMatcherCopy == null) {
            publicSuffixMatcherCopy = PublicSuffixMatcherLoader.getDefault();
        }
        //中間邏輯=========
   		return new InternalHttpClient((ClientExecChain)execChain, (HttpClientConnectionManager)connManagerCopy, (HttpRoutePlanner)routePlannerCopy, cookieSpecRegistryCopy, (Lookup)authSchemeRegistryCopy, (CookieStore)defaultCookieStore, (CredentialsProvider)defaultCredentialsProvider, this.defaultRequestConfig != null ? this.defaultRequestConfig : RequestConfig.DEFAULT, closeablesCopy);
    }

方法最後返回http請求client的時候,會做一個判斷有沒有設置自定義的請求配置requestconfig,如果設置了用自定義的,如果沒設置,用工具類默認的,那麼默認的配置到底是什麼呢?
在這裏插入圖片描述
在這裏插入圖片描述
問題到現在基本很明瞭了,這種client的默認配置如果請求一直沒響應會一直等待,外部請求過來我們請求其他數據源外部數據,但因爲其他數據源異常沒有及時返回數據給我們導致整個服務卡死,知道原因後解決方法就比較簡單了。修改後的http工具類如下:

public class HttpUtil {
	
	 private static Logger logger= LoggerFactory.getLogger(HttpUtil.class);
	 
	public static String postJson(String url, String body) throws Exception {
		return post(url, body, "application/json");
	}

	public static String postForm(String url, String body) throws Exception {
		return post(url, body, "application/x-www-form-urlencoded");
	}

	public static String post(String url, String body, String contentType) throws Exception {
		RequestConfig defaultRequestConfig = RequestConfig.custom()
				.setConnectTimeout(5000) //連接時間
				.setSocketTimeout(5000) //請求處理時間
				.setConnectionRequestTimeout(3000) //從連接池獲取連接超時時間
				.build();
		CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig).build();
		HttpPost httpPost = new HttpPost(url);
		httpPost.addHeader("Content-Type", contentType);
		httpPost.setEntity(new StringEntity(body, Charset.forName("UTF-8")));

		CloseableHttpResponse response = httpClient.execute(httpPost);
		HttpEntity entity = response.getEntity();
		String responseContent = EntityUtils.toString(entity, "UTF-8");

		response.close();
		httpClient.close();
		return responseContent;
	}
}

注:關於超時時間的參數具體設置值需要根據自己的業務需求自定義修改,不必照搬
至此,問題解決,針對這個問題有如下反思:
1、每次用一個不熟悉的技術,需要熟悉這個技術相關api,不能單純會用就好,需要考慮到後續的擴展,穩定性等因素
2、排查問題有優先級,先排除容易排除的因素,然後再針對性排查

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章