前言:本文的解决方案其实不是根本解决方式,因为默认时长30s,操作es都没有返回,这个需要考虑到在使用es的时候,怎么样才能更快返回,去提高es的读写性能,建议阅读有关提高es读写性能的博客,会很有用,但是如果只是想暂时不抛这个错,可以看一下这个解决方式
使用RestClient请求Es抛错listener timeout after waiting for [30000] ms
异常如下:
java.io.IOException: listener timeout after waiting for [30000] ms
at org.elasticsearch.client.RestClient$SyncResponseListener.get(RestClient.java:899)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:227)
at org.elasticsearch.client.RestHighLevelClient.performRequest(RestHighLevelClient.java:1256)
at org.elasticsearch.client.RestHighLevelClient.performRequestAndParseEntity(RestHighLevelClient.java:1231)
at org.elasticsearch.client.RestHighLevelClient.bulk(RestHighLevelClient.java:329)
at com.changjia.commodity.task.util.EsUtil.saveAll(EsUtil.java:146)
或者抛错:java.net.SocketTimeoutException: 30,000 milliseconds timeout on connection http-outgoing-3 [ACTIVE]
aused by: java.net.SocketTimeoutException: 30,000 milliseconds timeout on connection http-outgoing-3 [ACTIVE]
at org.elasticsearch.client.RestClient$SyncResponseListener.get(RestClient.java:928)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:227)
at org.elasticsearch.client.RestHighLevelClient.performRequest(RestHighLevelClient.java:1256)
at org.elasticsearch.client.RestHighLevelClient.performRequestAndParseEntity(RestHighLevelClient.java:1231)
at org.elasticsearch.client.RestHighLevelClient.search(RestHighLevelClient.java:730)
at com.changjia.commodity.task.es.impl.EsSearchServiceImpl.search(EsSearchServiceImpl.java:32)
... 85 common frames omitted
Caused by: java.net.SocketTimeoutException: 30,000 milliseconds timeout on connection http-outgoing-3 [ACTIVE]
at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.timeout(HttpAsyncRequestExecutor.java:387)
at org.apache.http.impl.nio.client.InternalIODispatch.onTimeout(InternalIODispatch.java:92)
at org.apache.http.impl.nio.client.InternalIODispatch.onTimeout(InternalIODispatch.java:39)
at org.apache.http.impl.nio.reactor.AbstractIODispatch.timeout(AbstractIODispatch.java:175)
at org.apache.http.impl.nio.reactor.BaseIOReactor.sessionTimedOut(BaseIOReactor.java:261)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.timeoutCheck(AbstractIOReactor.java:502)
at org.apache.http.impl.nio.reactor.BaseIOReactor.validate(BaseIOReactor.java:211)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:280)
at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104)
at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:591)
... 1 common frames omitted
解决方案:实现RestClientBuilderCustomizer接口,设置过期时间更长:
@Service
public class EsClientConfiguration implements RestClientBuilderCustomizer {
@Override
public void customize(RestClientBuilder builder) {
//第一个异常解决方案
builder.setMaxRetryTimeoutMillis(300 * 1000);
//第二个异常解决方案
RestClientBuilder.RequestConfigCallback configCallback = new RestClientBuilder.RequestConfigCallback() {
@Override
public org.apache.http.client.config.RequestConfig.Builder customizeRequestConfig(org.apache.http.client.config.RequestConfig.Builder requestConfigBuilder) {
return requestConfigBuilder
.setConnectTimeout(30000)
.setSocketTimeout(300 * 1000);//更改客户端的超时限制默认30秒现在改为5分钟
}
};
builder.setRequestConfigCallback(configCallback);
}
}
这样就可以了。
下面是第一个异常找到解决方案的过程:
看到异常后打开
RestClient.java 看到899行
看来看去被绕晕了,于是用xmind记录了一下看的过程,完成以后觉得这是一次不错的经历,并且笔记完整,于是记录一下:
这是899行抛错的经过,因为CountDownLatch等待了 timeout毫秒还没等到,于是就抛出了这个异常,
于是就找这个timeout怎么来的,是RestClient的静态内部类SyncResponseListener的这个构造方法设置了这个过期时间,
然后这个构造函数是被下面这个方法调用了,参数maxRetryTimeoutMillis是RestClient的一个私有属性
然后它的值是在执行RestClient的构造函数的时候传进来的。
RestClient的构造函数是RestClientBuilder的build()执行的,过期时间maxRetryTimeout是RestClientBuilder的私有属性,并且默认值是
这个时间可以被RestClientBuilder的这个方法设置的。
那RestClientBuilder和我们使用的RestHighLevelClient有什么关系尼,从上面的异常可以看出
RestHighLevelClient调用RestClient的performRequest()方法出现了这次异常。
从抛错的地方看出RestClient是RestHighLevelClient的一个私有属性,并且被设置的最终原因是:下面第二张图中的第一个方法。
所以问题变成了,这个RestHighLevelClient的构造函数是在什么时候被调用的,RestClientBuilder是什么时候生成的,我怎么才能调用RestClientBuilder的设置时间的这个方法,对RestClientBuilder这个实例操作,设置这个时间。
于是从自己的代码出发,我使用的 RestHighLevelClient是被@Resource注入的,于是我找到了下面这个java配置
这个RestHighLevelClient实例被传入了RestClientBuilder。
RestClientBuilder实例是怎么来的尼
customizer.customize(builder)方法,点进去,发现这是一个接口,我们看一下这个接口的名字,好像感觉到了点什么,我们再看一下这个接口的注释。破案了。