一、问题背景

最近在做ES清空指定index下的指定type类型数据时,发现在大数据量情况下删除的时候会比较慢,会超过自己设定的socketTimeout时间,需要提升性能。

二、集群环境

ElasticSearch版本: 阿里云 5.5.3

删除的数据量大小:7000w

三、原始日志

es Java连接超时时间 es socket time out_ElasticSearch

可以看到日志打印时间从13:44:11-14:14:16,删除30分钟后,程序抛出sockectTimeout异常

四、代码

获取ES restClient 代码,参考阿里云给的示例 :Java REST Client

public static RestClient getClient(Configuration config){
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY,
                new UsernamePasswordCredentials(config.getString(Key.USERNAME), config.getString(Key.PASSWORD)));
        final RequestConfig reqConf = RequestConfig.custom().setConnectTimeout(60*1000)
                .setSocketTimeout(30*60*1000)
                .setConnectionRequestTimeout(30*1000).build();

        RestClient client = RestClient.builder(getHosts(config)).setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
            @Override
            public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
                httpClientBuilder.setDefaultRequestConfig(reqConf);
                return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
            }
        }).setMaxRetryTimeoutMillis(60*60*1000).build();
        return client;
    }

可以看到上边的代码中设定的socketTimout时间为30分钟。接下来可以看到删除ES下指定index下的指定type代码段:

LOG.info("执行es清空开始");
String esIndex = originalConfig.getString(Key.INDEX);
String esType = originalConfig.getString(Key.TYPE);
String path = esIndex + "/" + esType + "/_delete_by_query";
RestClient client = null;
try {
    client = EsClientUtil.getClient(originalConfig);
    HttpEntity httpEntity = new StringEntity(Key.queryAll, "UTF-8");
    Response response = client.performRequest("POST", path , Collections.<String, String>emptyMap(), httpEntity, new BasicHeader(HTTP.CONTENT_TYPE,"application/json"));
    StatusLine line = response.getStatusLine();
    LOG.info("清空es返回结果 {}", JSON.toJSONString(line));
    if(line != null && line.getStatusCode() == Key.SUCCESS ){
        LOG.info("执行清空es成功");
    }
}catch (Exception e){
    LOG.error("执行清空es出现异常信息",e);
}finally {
    if(client != null){
        try {
            client.close();
        } catch (IOException e) {
            LOG.error("关闭Es RestClient失败",e);
        }
    }
}
LOG.info("执行清空es结束");

主要是使用delete_by_query实现的。

因此有2种方式:1、调大超时时间,但这个显然不治标 2、需要看一下这个API上是否有可以调优的参数设置

参考官网给出的API说明文档:Delete by query API

发现了2个可以进行调优的参数:

es Java连接超时时间 es socket time out_ElasticSearch_02

每次es删除时,默认是先从上到下查询出100条记录然后再进行删除。

es Java连接超时时间 es socket time out_ElasticSearch_03

可以理解为,默认值是一个线程在进行查询数据并删除,当设置这个slices值时,会将es下的数据进行切分,启动多个task去做删除,理解为多线程执行操作 。

五、调优

在代码里加上找到的调优参数: 

LOG.info("执行es清空开始");
String esIndex = originalConfig.getString(Key.INDEX);
String esType = originalConfig.getString(Key.TYPE);
int size = originalConfig.getInt(Key.DEL_SCROLL_SIZE, DEFAULT_SCROLL_SIZE);
int sliceSize = originalConfig.getInt(Key.ES_SLICE_SIZE, DEFAULT_SLICES);

// conflicts=proceed参数,指的是当删除遇到版本冲突时,继续删除;默认不写,es遇到冲突时会直接终止。
String path = esIndex + "/" + esType + "/_delete_by_query?conflicts=proceed&scroll_size=" + size + "&slices=" + sliceSize;
RestClient client = null;
try {
    client = EsClientUtil.getClient(originalConfig);
    HttpEntity httpEntity = new StringEntity(Key.queryAll, "UTF-8");
    LOG.info("清空es请求路径为 {}", path);
    Response response = client.performRequest("POST", path , Collections.<String, String>emptyMap(), httpEntity, new BasicHeader(HTTP.CONTENT_TYPE,"application/json"));
    StatusLine line = response.getStatusLine();
    LOG.info("清空es返回结果 {}", JSON.toJSONString(line));
    if(line != null && line.getStatusCode() == Key.SUCCESS ){
        LOG.info("执行清空es成功");
    }
}catch (Exception e){
    LOG.error("执行清空es出现异常信息",e);
}finally {
    if(client != null){
        try {
            client.close();
        } catch (IOException e) {
            LOG.error("关闭Es RestClient失败",e);
        }
    }
}
LOG.info("执行清空es结束");

测试数据

scroll_size

slices

耗时

3000

2

>30min

3000

5

3min16s

3000

10

5min59s 这个记录有待考量,与底下对比不符

5000

5

3min33s

5000

10

3min34s

10000

5

5min01s

10000

10

4min50s

综上可以看出,增加这2个参数的性能提升很明显,从原来的大于30min缩短到3min左右,性能提升了10倍左右。 

六、总结

对于调用第三方服务API时,需要多加注意可能存在的性能问题,然后也需要更加细致去看提供的文档,很多东西其实文档里都有写。