OutOfMemoryError with elasticsearch REST Java 客户端通过 apache http nio
OutOfMemoryError with elasticsearch REST Java client via apache http nio
我们正在使用 elasticsearch REST Java 客户端(我们在 Java 7 上,所以不能使用普通的 elasticsearch Java 客户端)与我们的 elasticsearch 服务器交互。这一切都很好,除了当我们试图对大约 1.3m 文档进行初始索引时。这运行了一段时间但是在几十万个文件之后我们得到了
20/06 21:27:33,153 ERROR [cid=51][stderr][write:71] (pool-837116-thread-1) Exception in thread "pool-837116-thread-1" java.lang.OutOfMemoryError: unable to create new native thread
20/06 21:27:33,154 ERROR [cid=51][stderr][write:71] (pool-837116-thread-1) at java.lang.Thread.start0(Native Method)
20/06 21:27:33,154 ERROR [cid=51][stderr][write:71] (pool-837116-thread-1) at java.lang.Thread.start(Thread.java:693)
20/06 21:27:33,154 ERROR [cid=51][stderr][write:71] (pool-837116-thread-1) at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor.execute(AbstractMultiworkerIOReactor.java:334)
20/06 21:27:33,154 ERROR [cid=51][stderr][write:71] (pool-837116-thread-1) at org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager.execute(PoolingNHttpClientConnectionManager.java:194)
20/06 21:27:33,154 ERROR [cid=51][stderr][write:71] (pool-837116-thread-1) at org.apache.http.impl.nio.client.CloseableHttpAsyncClientBase.run(CloseableHttpAsyncClientBase.java:64)
20/06 21:27:33,155 ERROR [cid=51][stderr][write:71] (pool-837116-thread-1) at java.lang.Thread.run(Thread.java:724)
接着是
java.lang.IllegalStateException: Request cannot be executed; I/O reactor status: STOPPED
at org.apache.http.util.Asserts.check(Asserts.java:46)
at org.apache.http.impl.nio.client.CloseableHttpAsyncClientBase.ensureRunning(CloseableHttpAsyncClientBase.java:90)
at org.apache.http.impl.nio.client.InternalHttpAsyncClient.execute(InternalHttpAsyncClient.java:123)
at org.elasticsearch.client.RestClient.performRequestAsync(RestClient.java:343)
at org.elasticsearch.client.RestClient.performRequestAsync(RestClient.java:325)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:218)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:191)
如您所见,Elasticsearch REST 客户端正在使用 apache http nio。我发现奇怪的是 nio 库正在为每个请求(或连接?)创建一个线程。从上面的日志中可以看到线程 (pool-837116-thread-1)。还有很多 I/O 个调度程序线程,并且数量在增加。
尽管如此,活动线程的总数似乎没有太大变化。
因此,似乎不是重用线程,而是为每个连接周期创建一个(或实际上是两个)新线程。
上传基本是:
1。创建客户端
restClient = RestClient.builder(new HttpHost(host.getHost(),host.getPort(),host.getProtocol())/*,new HttpHost(host.getHost(),host.getPort()+1,host.getProtocol())*/)
.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
@Override
public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
return httpClientBuilder
.setDefaultCredentialsProvider(credsProvider)
}
}).setMaxRetryTimeoutMillis(30000).build();
2。发送带有 json 正文的请求并关闭客户端
try{
HttpEntity entity = new NStringEntity(json,ContentType.APPLICATION_JSON);
Response indexResponse = restClient.performRequest("PUT", endpoint, parameters,entity,header);
log.debug("Response #0 #1", indexResponse,indexResponse.getStatusLine());
log.debug("Entity #0",indexResponse.getEntity());
}finally{
if(restClient!=null){
log.debug("Closing restClient #0", restClient);
restClient.close();
}
}
这正常吗?为什么 apache nio 不重用线程?这是 elasticsearch REST 客户端、apache nio 还是我的代码的问题?我在 restClient 上调用 close,不知道我还应该做什么。
我尝试将 IO Reactor 上的线程数设置为 1:
restClient = RestClient.builder(new HttpHost(host.getHost(),host.getPort(),host.getProtocol())/*,new HttpHost(host.getHost(),host.getPort()+1,host.getProtocol())*/)
.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
@Override
public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
return httpClientBuilder
.setDefaultCredentialsProvider(credsProvider)
.setDefaultIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(1).build()); //set to one thread
}
}).setMaxRetryTimeoutMillis(30000).build();
但这并没有改变线程重用的任何内容。
我找到了 OutOfMemoryError 的原因。尽管我使用的是 try - finally 块,我将在其中关闭客户端 - 在该块之外抛出异常(该块没有涵盖所有内容 D'oh)。但是创建这么多线程看起来还是不对(虽然整体线程数并没有明显增加)。
郑重声明:我在使用 ElasticSearch 时也 运行 遇到了这个错误 IllegalStateException: Request cannot be executed; I/O reactor status: STOPPED
。
根本原因在于我的应用程序,它多次尝试使用同一个帐户登录,这反过来导致在相应索引上出现多个不必要的 save() 和 retrieveById() 语句。
要诊断类似的问题,它有助于仔细检查堆栈跟踪,并且 - 如果错误发生在几个不同的单元测试中 - 寻找那里的任何共性,例如在索引上调用相同的方法。
我们正在使用 elasticsearch REST Java 客户端(我们在 Java 7 上,所以不能使用普通的 elasticsearch Java 客户端)与我们的 elasticsearch 服务器交互。这一切都很好,除了当我们试图对大约 1.3m 文档进行初始索引时。这运行了一段时间但是在几十万个文件之后我们得到了
20/06 21:27:33,153 ERROR [cid=51][stderr][write:71] (pool-837116-thread-1) Exception in thread "pool-837116-thread-1" java.lang.OutOfMemoryError: unable to create new native thread
20/06 21:27:33,154 ERROR [cid=51][stderr][write:71] (pool-837116-thread-1) at java.lang.Thread.start0(Native Method)
20/06 21:27:33,154 ERROR [cid=51][stderr][write:71] (pool-837116-thread-1) at java.lang.Thread.start(Thread.java:693)
20/06 21:27:33,154 ERROR [cid=51][stderr][write:71] (pool-837116-thread-1) at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor.execute(AbstractMultiworkerIOReactor.java:334)
20/06 21:27:33,154 ERROR [cid=51][stderr][write:71] (pool-837116-thread-1) at org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager.execute(PoolingNHttpClientConnectionManager.java:194)
20/06 21:27:33,154 ERROR [cid=51][stderr][write:71] (pool-837116-thread-1) at org.apache.http.impl.nio.client.CloseableHttpAsyncClientBase.run(CloseableHttpAsyncClientBase.java:64)
20/06 21:27:33,155 ERROR [cid=51][stderr][write:71] (pool-837116-thread-1) at java.lang.Thread.run(Thread.java:724)
接着是
java.lang.IllegalStateException: Request cannot be executed; I/O reactor status: STOPPED
at org.apache.http.util.Asserts.check(Asserts.java:46)
at org.apache.http.impl.nio.client.CloseableHttpAsyncClientBase.ensureRunning(CloseableHttpAsyncClientBase.java:90)
at org.apache.http.impl.nio.client.InternalHttpAsyncClient.execute(InternalHttpAsyncClient.java:123)
at org.elasticsearch.client.RestClient.performRequestAsync(RestClient.java:343)
at org.elasticsearch.client.RestClient.performRequestAsync(RestClient.java:325)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:218)
at org.elasticsearch.client.RestClient.performRequest(RestClient.java:191)
如您所见,Elasticsearch REST 客户端正在使用 apache http nio。我发现奇怪的是 nio 库正在为每个请求(或连接?)创建一个线程。从上面的日志中可以看到线程 (pool-837116-thread-1)。还有很多 I/O 个调度程序线程,并且数量在增加。
尽管如此,活动线程的总数似乎没有太大变化。 因此,似乎不是重用线程,而是为每个连接周期创建一个(或实际上是两个)新线程。 上传基本是:
1。创建客户端
restClient = RestClient.builder(new HttpHost(host.getHost(),host.getPort(),host.getProtocol())/*,new HttpHost(host.getHost(),host.getPort()+1,host.getProtocol())*/)
.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
@Override
public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
return httpClientBuilder
.setDefaultCredentialsProvider(credsProvider)
}
}).setMaxRetryTimeoutMillis(30000).build();
2。发送带有 json 正文的请求并关闭客户端
try{
HttpEntity entity = new NStringEntity(json,ContentType.APPLICATION_JSON);
Response indexResponse = restClient.performRequest("PUT", endpoint, parameters,entity,header);
log.debug("Response #0 #1", indexResponse,indexResponse.getStatusLine());
log.debug("Entity #0",indexResponse.getEntity());
}finally{
if(restClient!=null){
log.debug("Closing restClient #0", restClient);
restClient.close();
}
}
这正常吗?为什么 apache nio 不重用线程?这是 elasticsearch REST 客户端、apache nio 还是我的代码的问题?我在 restClient 上调用 close,不知道我还应该做什么。
我尝试将 IO Reactor 上的线程数设置为 1:
restClient = RestClient.builder(new HttpHost(host.getHost(),host.getPort(),host.getProtocol())/*,new HttpHost(host.getHost(),host.getPort()+1,host.getProtocol())*/)
.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
@Override
public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
return httpClientBuilder
.setDefaultCredentialsProvider(credsProvider)
.setDefaultIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(1).build()); //set to one thread
}
}).setMaxRetryTimeoutMillis(30000).build();
但这并没有改变线程重用的任何内容。
我找到了 OutOfMemoryError 的原因。尽管我使用的是 try - finally 块,我将在其中关闭客户端 - 在该块之外抛出异常(该块没有涵盖所有内容 D'oh)。但是创建这么多线程看起来还是不对(虽然整体线程数并没有明显增加)。
郑重声明:我在使用 ElasticSearch 时也 运行 遇到了这个错误 IllegalStateException: Request cannot be executed; I/O reactor status: STOPPED
。
根本原因在于我的应用程序,它多次尝试使用同一个帐户登录,这反过来导致在相应索引上出现多个不必要的 save() 和 retrieveById() 语句。
要诊断类似的问题,它有助于仔细检查堆栈跟踪,并且 - 如果错误发生在几个不同的单元测试中 - 寻找那里的任何共性,例如在索引上调用相同的方法。