ES 查询超时时间设置(亲测有效)

首先吐槽下ES的文档真的是非常乱而且不好找,尤其是java api对应的部分,写的内容很少,很多东西都没有涉及到。
还有就是,es的timeout设置为了简便,参数居然是字符串……。1毫秒对应:"1ms",1纳秒对应:"1nanos"也是奇葩的很。对应的源码也没注释,真是用起来恶心的不行。

ES8+ Java API(低版本应该也差不多)查询超时设置(注意是客户端发起请求的超时设置,不是连接超时设置!!),目前我自己试过有效果的三个配置:

  1. RequestConfig.Builder().socketTimeout
  2. new SubmitRequest.Builder().timeout(esTimeout)
  3. new SubmitRequest.Builder().waitForCompletionTimeout(new Time.Builder().time(esTimeout).build()).build();

1、socketTimeout

RequestConfig.Builder().socketTimeout设置的是client等待从Elasticsearch节点接收响应的超时时间。

代码示例:

RestClientBuilder builder = RestClient.builder(hosts);
        builder.setRequestConfigCallback(requestConfigBuilder -> {
            requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeout);
            requestConfigBuilder.setConnectTimeout(connectTimeout);
            requestConfigBuilder.setSocketTimeout(socketTimeout);
            return requestConfigBuilder;
        });
        // 创建一个低阶的Rest客户端
        RestClient restClient = builder.build();

优点:

  • 超时会抛异常,符合我们写超时的习惯。配置简单。
  • 支持knn等查询场景,其实相当于就是请求socket的超时时间,相对来说比较底层,非ES特有。

缺点:

  • 由于是client创建时配置,没法动态的去控制修改超时时间。

2、timeout

new SubmitRequest.Builder().timeout(esTimeout) 这个相信很多人有设置过,但是用起来会感觉有种设置了却不生效的感觉。其实并不是不生效,我们看看这个配置的注释:

/**
* Specifies the period of time to wait for a response from each shard. If no
* response is received before the timeout expires, the request fails and
* returns an error. Defaults to no timeout.
* <p>
* API name: {@code timeout}
*/

也就es每个shard的查询超时时间,这个基本是都是微妙到纳秒级别的,只要es集群正常,基本上很难触发。
网上有对这个timeout觉得太容易让人混淆的讨论:

点击跳转具体地址

使用后的dsl类似如下:

POST /index_name/_async_search?wait_for_completion_timeout=5nanos
{"query":xxx,..."timeout":"5nanos"}

代码示例:

 SubmitRequest.Builder builder = new SubmitRequest.Builder().timeout(esTimeout)
                        .index("xxx")
                        .query(xxx)
                        .size(100);

优点

  • 不予置评,暂时还没有执行过单shard查询慢的情况

缺点

  • 触发条件苛刻,并非我们实际的整个请求的超时

3、waitForCompletionTimeout

new SubmitRequest.Builder().waitForCompletionTimeout(new Time.Builder().time(esTimeout).build()).build(); 直接看注释吧:

/**
* Specify the time that the request should block waiting for the final response
* <p>
* API name: {@code wait_for_completion_timeout}
*/

从描述就可以看出,这个和timeout不一样,是es针对请求的,它真正执行时的es dsl是这样的:

POST /index_name/_async_search?wait_for_completion_timeout=5nanos

代码示例:

SubmitRequest.Builder builder = new SubmitRequest.Builder()
                        .index("xxx")
                        .query(xxx)
                        .size(100);
SubmitRequest req = builder.waitForCompletionTimeout(new Time.Builder().time(esTimeout).build()).build();
                SubmitResponse<Map> submit = elasticsearchClient.asyncSearch().submit(req, Map.class);

优点:

  • 能够真正实现整个查询执行超时返回
  • 通过Apollo等动态配置,服务不需重启就能够动态的修改超时时间

缺点:

  • 部分高级语法不支持,如knn查询

总结

综上,在不涉及到es高级语法时,建议使用waitForCompletionTimeout;其他情况则使用socketTimeout最好。

THE END
分享
二维码
打赏