ElasticSearch-delete_by_query大数据量删除时,导致SocketTimeout的问题

一、问题背景

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

二、集群环境

ElasticSearch版本: 阿里云 5.5.3

删除的数据量大小:7000w

三、原始日志

可以看到日志打印时间从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删除时,默认是先从上到下查询出100条记录然后再进行删除。

可以理解为,默认值是一个线程在进行查询数据并删除,当设置这个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_sizeslices耗时
30002>30min
300053min16s
3000105min59s 这个记录有待考量,与底下对比不符
500053min33s
5000103min34s
1000055min01s
10000104min50s

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

六、总结

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

 

 

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
如果要删除 Elasticsearch 中的大数据,可以使用以下两种方式: 1. 使用 Scroll API 进行批删除 Scroll API 可以帮助我们在 Elasticsearch 中遍历大数据,以便进行批操作。具体步骤如下: - 使用 Search API 查询出要删除的数据,设置 `scroll` 参数以便获取全部数据。 ``` POST /{index}/_search?scroll=1m { "query": { // 查询语句,可以根据具体需求进行设置 } } ``` - 使用 Scroll API 获取全部数据,并进行批删除。 ``` POST /_search/scroll { "scroll_id": "{scroll_id}", "scroll": "1m" } POST /{index}/_delete_by_query { "query": { "ids": { "values": ["id_1", "id_2", ..., "id_n"] } } } ``` 其中 `{scroll_id}` 是第一次查询结果返回的 `_scroll_id` 字段,`{index}` 是要删除的索引名称,`id_1` 到 `id_n` 是要删除的文档 ID。 2. 使用 Curator 进行批删除 Curator 是一个 Elasticsearch 索引管理工具,可以帮助我们进行索引的批操作。具体步骤如下: - 安装 Curator。 ``` pip install elasticsearch-curator ``` - 创建一个删除索引数据的配置文件。 ``` actions: 1: action: delete_indices description: >- Delete indices older than 30 days (based on index name). options: ignore_empty_list: True disable_action: False filters: - filtertype: pattern kind: prefix value: logstash- - filtertype: age source: name direction: older timestring: '%Y.%m.%d' unit: days unit_count: 30 ``` 其中 `value` 是要删除的索引名称前缀,`unit_count` 是要删除的数据的间范围。 - 运行 Curator。 ``` curator --config curator.yml delete_indices.yml ``` 其中 `curator.yml` 是 Curator 的配置文件名称,`delete_indices.yml` 是删除索引数据的配置文件名称。 以上两种方式都可以帮助我们批删除 Elasticsearch 中的数据。具体选择哪种方式,要根据实际情况进行决定。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值