繁体   English   中英

Elasticsearch Java High-Level REST Client 建立一堆TCP连接,索引数据后不关闭

[英]Elasticsearch Java High-Level REST Client establish a bunch of TCP connection and doesn't close them after indexing data

我有一个每秒运行一次的定期作业(这是可配置的)。

在这份工作中,我首先创建了一个到 Elasticsearch 服务器的连接:

RestHighLevelClient client = new RestHighLevelClient(
                    RestClient.builder(new HttpHost(address, port, "http")));

然后我检查是否存在名为test的特殊索引。 如果它不存在,我会先创建它。

GetIndexRequest indexRequest = new GetIndexRequest();
indexRequest.indices("test");
boolean testIndexIsExists = false;
try {           
     testIndexIsExists = client.indices().exists(indexRequest, RequestOptions.DEFAULT); 
    } catch (IOException ioe) {
    logger.error("Can't check the existence of test index in Elasticsearch!");  
}
if(testIndexIsExists) {
     // bulk request...
} else {
    CreateIndexRequest testIndex = new CreateIndexRequest("test");
    try {   
        testIndex.mapping("doc", mappingConfiguration);
        client.indices().create(testIndex, RequestOptions.DEFAULT);
        // bulk request...  
    } catch (IOException ioe) { 
        logger.error("Can't create test index in Elasticsearch");
    }   
}

在做了一个接近 2000 个文档的批量请求之后,我关闭了 Elasticsearch 客户端连接:

client.close();

Java 高级 REST 客户端版本:

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>6.4.0</version>
</dependency>

我的问题是一堆已经建立但没有关闭的 TCP 连接。 这些 TCP 连接会随着时间的推移占用所有操作系统 TCP 连接。

另一方面,我有点困惑。 RestHighLevelClient实例应该是整个应用程序的单例对象,还是我必须在每个作业运行周期中创建一个新实例并在完成该作业后关闭该实例?

高级客户端已经为您维护了一个连接池,因此我将其用作单例。 不断地创建和关闭连接池代价高昂,而且客户端和底层 HTTP 连接池是线程安全的。 此外,在客户端上调用close()只是委托给 Apache HTTP 客户端shutdown()方法,因此您受他们如何处理清理和释放资源的支配。

如果您使用的是 Spring 或其他一些 DI 框架,则很容易创建可以根据需要注入的客户端的单例实例。 您可以将调用添加到client.close()作为 bean 关闭/销毁生命周期阶段的一部分。

使用 Spring Boot 的快速示例:

@Configuration
@ConditionalOnClass(RestHighLevelClient.class)
public class ElasticSearchConfiguration {

    @Value("${elasticsearch.address}")
    String address;

    @Value("${elasticsearch.port}")
    int port;

    @Bean(destroyMethod = "close")
    public RestHighLevelClient restHighLevelClient() {
        return new RestHighLevelClient(
                RestClient.builder(new HttpHost(address, port, "http")));
    }
}

注意:在这种情况下,Spring 会自动检测到 bean 有close方法,并在 bean 销毁时为您调用它。 其他框架可能要求您指定应如何处理关闭。

RestHighLevelClient通常应该是单例的,除非你有充分的理由。 例如,如果您的作业每小时而不是每分钟运行一次,则创建新实例并在作业完成后关闭它可能是有意义的。

如果您确定在所有情况下都调用close() (例如您没有错过任何异常),那么我的下一个猜测是弹性客户端中的错误。

看起来他们忘记在存在调用中使用响应: https : //github.com/elastic/elasticsearch/blob/v6.4.0/client/rest-high-level/src/main/java/org/elasticsearch /client/RestHighLevelClient.java#L1419

你能在没有exists调用的情况下进行测试吗?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM