1.更新操作版本冲突异常,乐观锁异常,报409
org.elasticsearch.client.ResponseException: method [POST], host [https://xxx.xx.xx.xx:9200], URI [/docs/_update/3269-60], status line [HTTP/1.1 409 Conflict]
{"error":{"root_cause":[{"type":"version_conflict_engine_exception","reason":"[3269-60]: version conflict, required seqNo [1411133], primary term [1]. current document has seqNo [1411134] and primary term [1]","index_uuid":"lgIyKKxKSYy5HpNnGNz6sg","shard":"0","index":"doc_index"}],"type":"version_conflict_engine_exception","reason":"[3269-60]: version conflict, required seqNo [1411133], primary term [1]. current document has seqNo [1411134] and primary term [1]","index_uuid":"lgIyKKxKSYy5HpNnGNz6sg","shard":"0","index":"doc_index"},"status":409}
at org.elasticsearch.client.RestClient.convertResponse(RestClient.java:347)
at org.elasticsearch.client.RestClient.access$1900(RestClient.java:108)
at org.elasticsearch.client.RestClient$1.completed(RestClient.java:397)
at org.elasticsearch.client.RestClient$1.completed(RestClient.java:393)
at org.apache.http.concurrent.BasicFuture.completed(BasicFuture.java:119)
at org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.responseCompleted(DefaultClientExchangeHandlerImpl.java:182)
at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.processResponse(HttpAsyncRequestExecutor.java:448)
at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.inputReady(HttpAsyncRequestExecutor.java:338)
at org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:265)
at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:87)
at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:40)
at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:121)
at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:162)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:337)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:276)
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)
at java.lang.Thread.run(Thread.java:745)
这个错误主要是在频繁更新文档时出现,原因是ES在更新文档时用乐观锁来保证更新操作的一致性,它会维护一个序列号,当一个线程执行更新操作前取得序列号后如果如果其他线程完成更新操作就会导致序列号增长,这时前一个线程执行更新操作时序列号小于当前序列号,从而引发乐观锁异常。
该问题的解决方式很简单。ES提供了失败重试参数,对于并发量不是特别高的应用,设置失败重试参数基本上就可以避免这类错误了。
elasticsearchAsyncClient.update(e -> e
.index(indexAlias)
.id(doc.getId())
.doc(doc)
.detectNoop(false)
.retryOnConflict(3), //失败后重试3次
ProcDocEsV.class)
.whenComplete((response, exception) -> {
// ....
});
2.连接超时异常
java.net.SocketTimeoutException: 30,000 milliseconds timeout on connection http-outgoing-15 [ACTIVE]
at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.timeout(HttpAsyncRequestExecutor.java:387)
at org.apache.http.impl.nio.client.InternalIODispatch.onTimeout(InternalIODispatch.java:98)
at org.apache.http.impl.nio.client.InternalIODispatch.onTimeout(InternalIODispatch.java:40)
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)
at java.lang.Thread.run(Thread.java:745)
这个问题可能的原因有两种:
(1)单次请求数据太多,设置的请求超时时间太小。ES默认的socketTimeout 和 connectTimeout 参数分别为30秒和1秒,可以根据需要调整参数,可以在配置ES连接的时候设置此参数。
RestClient restClient=RestClient
.builder(new HttpHost(host, Integer.parseInt(port), "https"))
.setRequestConfigCallback(
requestConfigBuilder -> requestConfigBuilder
.setConnectTimeout(5000)
.setSocketTimeout(60000))
.build();
(2)ES服务长时间没有收到请求时,会关闭应用之间建立的连接,这时发起请求并不会先判断连接是否可达。需要设置保活策略,保证连接不被断开。
RestClient restClient=RestClient
.builder(new HttpHost(host, Integer.parseInt(port), "https"))
.setHttpClientConfigCallback(hc -> hc
.setSSLContext(sslContext)
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.setKeepAliveStrategy((response, context) -> Duration.ofMinutes(5).toMillis()))
.build();
参考博文:
Elasticsearch High Level Rest Client偶现访问集群超时的问题定位与解决-腾讯云开发者社区-腾讯云 (tencent.com)