簡體   English   中英

使用Elasticsearch的RestClient時如何解決“對等連接重置”

[英]How to get around “connection reset by peer” when using Elasticsearch's RestClient

我們正在針對Elasticsearch 5.6.6服務器使用Hibernate Search 5.10.3.Final。

直接發出FullTextQueries時,我們的應用程序和ES之間的連接似乎很牢固,也許b / c HibernateSearch有一些內置的重試方法,但是我不確定,但是,在我們的應用程序中,我們使用Elasticsearch的RestClient發出直接調用。 _analyze,這是我們的防火牆在30分鍾后關閉空閑連接時connection reset by peer IOException connection reset by peer連接的地方。

java.io.IOException: Connection reset by peer
    at sun.nio.ch.FileDispatcherImpl.read0(Native Method) ~[?:1.8.0_131]
    at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39) ~[?:1.8.0_131]
    at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223) ~[?:1.8.0_131]
    at sun.nio.ch.IOUtil.read(IOUtil.java:197) ~[?:1.8.0_131]
    at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380) ~[?:1.8.0_131]
    at org.apache.http.impl.nio.reactor.SessionInputBufferImpl.fill(SessionInputBufferImpl.java:204) ~[httpcore-nio-4.4.5.jar:4.4.5]
    at org.apache.http.impl.nio.codecs.AbstractMessageParser.fillBuffer(AbstractMessageParser.java:136) ~[httpcore-nio-4.4.5.jar:4.4.5]
    at org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:241) ~[httpcore-nio-4.4.5.jar:4.4.5]
    at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:81) ~[httpasyncclient-4.1.2.jar:4.1.2]
    at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:39) ~[httpasyncclient-4.1.2.jar:4.1.2]
    at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:114) ~[httpcore-nio-4.4.5.jar:4.4.5]
    at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:162) ~[httpcore-nio-4.4.5.jar:4.4.5]
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:337) ~[httpcore-nio-4.4.5.jar:4.4.5]
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315) ~[httpcore-nio-4.4.5.jar:4.4.5]
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:276) ~[httpcore-nio-4.4.5.jar:4.4.5]
    at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104) ~[httpcore-nio-4.4.5.jar:4.4.5]
    at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:588) ~[httpcore-nio-4.4.5.jar:4.4.5]
    at java.lang.Thread.run(Thread.java:748) ~[?:1.8.0_131]

為了完整起見,這是我們大多數的RestClient代碼:

SearchFactory searchFactory = fts.getSearchFactory();
IndexFamily indexFamily = searchFactory.getIndexFamily(ElasticsearchIndexFamilyType.get());
ElasticsearchIndexFamily elasticsearchIndexFamily = indexFamily.unwrap(ElasticsearchIndexFamily.class);
RestClient restClient = elasticsearchIndexFamily.getClient(RestClient.class);

Map<String, String> rawData = new HashMap<>();
rawData.put("analyzer", analyzer);
rawData.put("text", text);

try {
    String jsonData = objectMapper.writeValueAsString(rawData);
    HttpEntity entity = new NStringEntity(jsonData, ContentType.APPLICATION_JSON);

    Response response = restClient.performRequest("GET", "vendor/_analyze", Collections.emptyMap(), entity);

    int statusCode = response.getStatusLine().getStatusCode();
    if (statusCode == HttpStatus.SC_OK) {
        // we parse the response here
    }
} catch (IOException e) {
    String message = "Error communicating with Elasticsearch!";
    logger.error(message, e);
    throw new IllegalStateException(message, e);
}

我們嘗試創建一個“心跳”,每分鍾使用RestClient發出一個小的“ _cluster /運行狀況”調用,但這似乎也不能完全解決問題。 甚至心跳有時也會因相同的IOException而失敗。

  1. 有人可以解釋HibernateSearch和ES之間的連接數(我認為默認情況下是20還是2,取決於ES集群是否存在),以及連接是以循環方式還是隨機方式使用的?
  2. 簡單重試RestClient是否會再次“喚醒”連接?
  3. 還是我們需要手動將連接重新連接到ES?
  4. 最后,是否存在可以解決此問題的現有休眠搜索設置,可能是hibernate.search.default.elasticsearch.discovery.enabled或其他設置?

問題說明

我假設您對30分鍾后防火牆關閉連接的解釋是正確的。

據我所知,Apache HTTP客戶端根據ConnectionKeepAliveStrategy決定保持給定連接有效的時間。 默認情況下,這是org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy ,這將使連接保持活動的時間與Elasticsearch服務器的響應中的Keep-Alive標頭所建議的時間一樣長,或者無限期地(如果Elasticsearch服務器不返回)這樣的標題響應。

我做了一些測試,顯然Elasticsearch不會返回任何Keep-Alive標頭,因此當前,連接可以無限期地重復使用,至少直到您的網絡將其殺死為止。

一旦連接被終止,您可以希望自動重試進入,但是只有在您有多個Elasticsearch節點時,它們才有效。 如果只有一個節點並且請求失敗,那么其余客戶端將不會在同一節點上重試。

因此,總的來說,失敗是可以預期的。 什么不是,是您僅用自己的客戶端代碼見證了失敗,但我想您可能忽略了日志中的某些錯誤的事實嗎?

解決方案(希望如此)

也許Apache HTTP客戶端可以在強制關閉連接時自動處理重新打開的連接,但是我找不到這種功能。

我也找不到一種方法使Elasticsearch服務器在其HTTP響應中添加一個Keep-Alive標頭。

如果您使用的是HTTP,而不是HTTPS(在這種情況下,我希望它是專用網絡),則可以配置網絡基礎結構以在每個HTTP消息中插入此類標頭。 如果您在諸如Apache服務器之類的代理后面使用Elasticsearch,那么您也應該能夠這樣做。

否則,為了在客戶端上顯式配置它,可以在Hibernate Search中使用org.hibernate.search.elasticsearch.client.spi.ElasticsearchHttpClientConfigurer擴展點。

警告 :此擴展點是一個SPI,最重要的是,它是實驗性的,這意味着它在任何較新版本的Hibernate Search中都可能以不兼容的方式進行更改。 在下一次升級中,即使是微升級,也可能必須更改代碼。 我們這邊沒有保證。

創建一個實現:

package com.acme.config;

import org.hibernate.search.elasticsearch.client.spi.ElasticsearchHttpClientConfigurer;

public class MyHttpConfigurer implements ElasticsearchHttpClientConfigurer {
   private static final int KEEP_ALIVE_MS = 20 * 60 * 1000; // 20 minutes
    @Override
    public void configure(HttpAsyncClientBuilder builder, Properties properties) {
        builder.setKeepAliveStrategy( (response, context) -> KEEP_ALIVE_MS );
    }
}

通過創建具有以下內容的META-INF/services/org.hibernate.search.elasticsearch.client.spi.ElasticsearchHttpClientConfigurer文件來注冊您的實現:

com.acme.config.MyHttpConfigurer

...您就完成了。

在調試模式下使用MyHttpConfigurer的斷點啟動應用程序以檢查其是否已執行,如果已執行,則HTTP客戶端應在20分鍾后自動停止使用空閑連接,並且您不會再遇到相同的問題。

回答您的問題

  1. 有人可以解釋HibernateSearch和ES之間的連接數(我認為默認情況下是20還是2,取決於ES集群是否存在),以及連接是以循環方式還是隨機方式使用的?

從文檔中:

hibernate.search.default.elasticsearch.max_total_connection 20(默認)

hibernate.search.default.elasticsearch.max_total_connection_per_route 2(默認)

它不取決於ES是否集群。 這取決於客戶端知道多少個節點/路由。 如果禁用了自動發現(默認為hibernate.search.default.elasticsearch.discovery.enabled false ),則客戶端已知的節點是您顯式配置的節點。 如果啟用了該功能,並且群集中有多個節點,則客戶端可能知道的節點數比您顯式配置的更多。

默認情況下,客戶端知道每個主機最多使用兩個連接,但總數不得超過20個。 因此,如果知道9個節點,則最多使用18個連接,如果知道10個節點,則最多使用20個連接,如果知道11個或更多節點,則仍然最多使用20個連接。

  1. 簡單重試RestClient是否會再次“喚醒”連接?

據我所知,它應該,但是那時我不知道是什么完全重置了您的連接,所以很難說。

  1. 還是我們需要手動將連接重新連接到ES?

我不認為你應該自己做。 連接會在非常低的級別自動進行管理。 不是通過Hibernate Search,甚至不是Rest Client,而是HTTP Client。

無論如何,如果您真的想那樣做,則必須以某種方式使用HTTP客戶端。 我不知道

  1. 最后,是否存在可以解決此問題的現有休眠搜索設置,可能是啟用了hibernate.search.default.elasticsearch.discovery.enabled或其他設置?

hibernate.search.default.elasticsearch.discovery.enabled僅在您需要更多連接並且您的Elasticsearch是集群的時才有用。 在您的情況下,似乎您的現有連接在一段時間后會被終止,因此即使您增加連接數,您仍然會遇到相同的問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM