RestClient的TimeOut和Can’t assign requested address問題排查及解決
問題背景
TimeOut問題
在項目中用到了es,因為請求比較簡單,是以使用了官方提供的Elasticsearch Java Low Level REST Client作為用戶端,但在最近優化es操作的過程中,使用了并行操作+異步請求的方式,在請求數量較大時,performRequestAsync方法的失敗回調中報錯:TimeOut,第一反應是連接配接逾時,但經過斷點調試,連接配接并沒有異常,在github上client項目的iisue中找到了原因,RestClient内部使用了連接配接池,在請求連接配接逾時時會報錯,是以TimeOut并不是連接配接逾時,而是連接配接池逾時的異常,通過在初始化client時設定參數為0的方式,可以關閉連接配接池逾時機制。如下所示。
RestClient restClient = RestClient.builder( )
.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
@Override
public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) {
requestConfigBuilder.setConnectTimeout(3000); // 連接配接逾時
requestConfigBuilder.setSocketTimeout(4000); // 資料請求逾時
requestConfigBuilder.setConnectionRequestTimeout(0); // 連接配接池逾時設定
return requestConfigBuilder;
}
}).setMaxRetryTimeoutMillis(5*60*1000).build();
Can’t assign requested addres問題
TIME_WAIT狀态
解決了連接配接逾時的問題,再次運作時,發現同一時間的請求數量較大時,又抛出了Can’t assign requested addres的異常,經過查閱,這個異常一般會在無可用端口時出現。在httpClient中出現這個異常一般是因為連接配接不是長連接配接,是以不斷地斷開重連,但關閉連接配接需要時間,是以在并發時出現無可用端口。我記得官方文檔中提到了RestClient預設是長連接配接,但以防萬一,在請求參數中加入了keepalive選項,結果問題不再出現,看來RestClient中預設并不是長連接配接。此處還需要繼續考證。
private static final RequestOptions COMMON_OPTIONS;
static {
RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
builder.addHeader("Connection", "keepalive");
COMMON_OPTIONS = builder.build();
}