
一、前言
小編最近在生產(chǎn)上遇到一個問題,解決完后立馬總結(jié)一下分享給大家,希望可以幫助到大家哈!
事情是這樣的,奇怪的現(xiàn)象,公司搭建的ElasticSearch,本來是用來提高檢索效率的,最近出現(xiàn)報錯了!
版本配置什么都沒變,奇怪的很!
ElasticSearch版本為7.6
問題:每隔幾個小時就會查詢不到,與?ElasticSearch?連接不上,刷新后查詢正常報錯為:?java.io.IOException: Connection reset by peer
拿著條件去kibana是可以查詢到的;
核心原因:
這個客戶端是長鏈接,服務(wù)端過期后自動關(guān)閉鏈接,客戶端繼續(xù)用原來的鏈接導(dǎo)致錯誤的!
二、前因后果
下面我們來詳細(xì)說一下報錯原因和解決方案哈:
1、報錯信息
java.io.IOException: Connection reset by peer
at org.elasticsearch.client.RestClient.extractAndWrapCause(RestClient.java:828)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:248)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:235)
at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1514)
at org.elasticsearch.client.RestHighLevelClient.performRequest(RestHighLevelClient.java:1484)
at org.elasticsearch.client.RestHighLevelClient.performRequestAndParseEntity(RestHighLevelClient.java:1454)
at org.elasticsearch.client.RestHighLevelClient.search(RestHighLevelClient.java:970)
2、原因與解決方案
上面也是說了原因,但是不太詳細(xì),下面詳細(xì)說一下原因哈!
ES會設(shè)置一個策略來進(jìn)行鏈接時間的控制,設(shè)置此連接的空閑持續(xù)時間!
我們可以看一下這個策略:
這個我們不配置會走這個策略,默認(rèn)-1為長鏈接,可循環(huán)重復(fù)使用、
我們只需要把這個策略換成我們的即可
@Contract(threading = ThreadingBehavior.IMMUTABLE)
public class DefaultConnectionKeepAliveStrategy implements ConnectionKeepAliveStrategy {
public static final DefaultConnectionKeepAliveStrategy INSTANCE = new DefaultConnectionKeepAliveStrategy();
@Override
public long getKeepAliveDuration(final HttpResponse response, final HttpContext context) {
Args.notNull(response, "HTTP response");
final HeaderElementIterator it = new BasicHeaderElementIterator(
response.headerIterator(HTTP.CONN_KEEP_ALIVE));
while (it.hasNext()) {
final HeaderElement he = it.nextElement();
final String param = he.getName();
final String value = he.getValue();
if (value != null && param.equalsIgnoreCase("timeout")) {
try {
return Long.parseLong(value) * 1000;
} catch(final NumberFormatException ignore) {
}
}
}
return -1;
}
}
服務(wù)器的TCP時間,我們可以查看一下:
cat /proc/sys/net/ipv4/tcp_keepalive_time

這里就是12分鐘,我們需要讓客戶端的鏈接時間小于服務(wù)器的keepalive時間!
這樣客戶端超過時間后就會重新獲取新鏈接,確保不會報錯哈??!
三、具體方案
編寫ElasticsearchProperties ,獲取nacos上的信息,方便修改!
@Data
@Component
@ConfigurationProperties(prefix = "spring.elasticsearch.rest")
public class ElasticsearchProperties {
private String uris;
private String username;
private String password;
}
編寫RestHighLevelClient配置類,使用我們的策略,看到其他教學(xué)還是使用以前的連接方式,現(xiàn)在RestClientBuilder里的RestClientBuilder是自動構(gòu)建連接的!
這里我們把RestClientBuilder注入,繼續(xù)放里面放新策略即可!
由于我們重寫RestHighLevelClient,它又依賴RestClientBuilder,原來RestClientBuilder會自動獲取用戶名密碼、連接地址,現(xiàn)在我們需要把用戶名密碼重新賦值一下哈!這樣就可以少一步輸入地址的哈!
這里設(shè)置10分鐘,沒有超過12分鐘!
@Configuration
public class ElasticsearchConfig {
@Autowired
private ElasticsearchProperties elasticsearchProperties;
@Autowired
private RestClientBuilder restClientBuilder;
@Bean
public RestHighLevelClient restHighLevelClient(){
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(elasticsearchProperties.getUsername(), elasticsearchProperties.getPassword()));
return new RestHighLevelClient(restClientBuilder.setHttpClientConfigCallback(requestConfig ->{
requestConfig.setKeepAliveStrategy((response, context) -> TimeUnit.MINUTES.toMillis(10));
requestConfig.setDefaultCredentialsProvider(credentialsProvider);
return requestConfig;
}));
}
}
看一下配置文件:

方案二:
如果不介意的話可以把錯誤捕獲起來,重新調(diào)用一下,第二次就會重新建立連接,這樣就不會有問題了,不過這種不太建議?。?/p>