Es 超时设置 high-level-client

照例,先上解决方案。我用的是es的high-level-client,不是spring-boot-starter-data-elasticsearch。

1、解决办法

1.1、自定义的RestHighLevelClient

在config配置类中,创建high-level-client时添加socket-timeout设置RequestConfigCallback。相关原理分析

@Configuration
public class ElasticRestJavaClientConfig {@Value("${elasticsearch.host}")private String hostList;@Beanpublic RestHighLevelClient restHighLevelClient() {//解析hostlist配置信息String[] split = hostList.split(",");//创建HttpHost数组,其中存放es主机和端口的配置信息HttpHost[] httpHostArray = new HttpHost[split.length];for (int i = 0; i < split.length; i++) {String item = split[i];httpHostArray[i] = new HttpHost(item.split(":")[0],Integer.parseInt(item.split(":")[1]), "http");}//核心,配置超时时间,添加configCallback,之后创建连接时会将超时设置到socket上RestClientBuilder.RequestConfigCallback requestConfigCallback = requestConfigBuilder -> requestConfigBuilder.setSocketTimeout(28_800_000);RestClientBuilder builder = RestClient.builder(httpHostArray).setRequestConfigCallback(requestConfigCallback);//创建RestHighLevelClient客户端return new RestHighLevelClient(builder);}
}

1.2、spring 装配的RestHighLevelClient

有两种方式,配置文件和自定义bean。相关原理spring 自动装配

1.2.1、配置文件

yml配置

spring:elasticsearch:rest:#单位毫秒read-timeout: 30connection-timeout: 30uris: ["http://localhost:9200","http://localhost:9201","http://localhost:9202"]

1.2.2 自定义bean

创建bean,并实现RestClientBuilderCustomizer即可

/*** 成为spring的bean*/
@Component
public class MyRestClientBuilderCustomizer implements RestClientBuilderCustomizer {@Overridepublic void customize(RestClientBuilder builder) {//配置超时RestClientBuilder.RequestConfigCallback configCallback = requestConfigBuilder -> requestConfigBuilder.setSocketTimeout(1000);//设置配置builder.setRequestConfigCallback(configCallback);}
}

2、分析-针对自定义的RestHighLevelClient

2.1、问题背景

我们的es集群需要定时做reindex操作,大概需要30分钟。在测试期间总是发现出现超时,抛出如下异常:

这张图片是专门为了测试用,超时设置的10毫秒。

按照方法名猜测,RestClient.performRequest里面执行超时,**extractAndWrapCause()**包装异常。接下来重点看看RestClient的方法

2.2、RestClient.performRequest

该方法是真正的执行方法,源码如下:

private Response performRequest(final NodeTuple<Iterator<Node>> nodeTuple,final InternalRequest request,Exception previousException) throws IOException {RequestContext context = request.createContextForNextAttempt(nodeTuple.nodes.next(), nodeTuple.authCache);HttpResponse httpResponse;try {//真正执行httpResponse = client.execute(context.requestProducer, context.asyncResponseConsumer, context.context, null).get();} catch(Exception e) {。。。。包装异常Exception cause = extractAndWrapCause(e);}   .....
}

可以看到,是真正执行是client这个成员变量执行的,我们看看这个client是什么

public class RestClient implements Closeable {//持有的成员变量private final CloseableHttpAsyncClient client;//构造方法RestClient(CloseableHttpAsyncClient client, Header[] defaultHeaders, List<Node> nodes, String pathPrefix,FailureListener failureListener, NodeSelector nodeSelector, boolean strictDeprecationMode) {this.client = client;this.defaultHeaders = Collections.unmodifiableList(Arrays.asList(defaultHeaders));this.failureListener = failureListener;this.pathPrefix = pathPrefix;this.nodeSelector = nodeSelector;this.warningsHandler = strictDeprecationMode ? WarningsHandler.STRICT : WarningsHandler.PERMISSIVE;setNodes(nodes);}
}

2.3 CloseableHttpAsyncClient

听名字应该是个httpClient,既然是httpClient应该有超时设置相关的,点进去看看。

public abstract class CloseableHttpAsyncClient implements HttpAsyncClient, Closeable {public abstract boolean isRunning();public abstract void start();@Overridepublic <T> Future<T> execute(final HttpAsyncRequestProducer requestProducer,final HttpAsyncResponseConsumer<T> responseConsumer,final FutureCallback<T> callback) {return execute(requestProducer, responseConsumer, HttpClientContext.create(), callback);}...
}

进去发现是模板抽象类,子类有多个,不太好确定是哪个。我们换个思路,该类的实例是RestClient的构造方法中有用到,我们可以RsetcLIent的构造方法的调用

2.3、RestClinet构造方法调用

通过idea在方法上右键,fine use找到调用关系

可以看到是在RestClientBuilder.build()方法中,进入看看

2.4、RestClientBuilder.build()

进入源码查看,可以看到build()中调用了createHttpClient()的方法。而且还有DEFAULT_SOCKET_TIMEOUT_MILLIS的关键字,一看就是和超时相关的

根据第一行代码,setSocketTimeout()返回了RequestConfig.Builder,说明RequestConfig.Builder中有超时相关的配置。同时在if判断的方法中,**requestConfigCallback.customizeRequestConfig()**看名字应该就是我们修改配置的地方。

综上所述,可以看到超时设置可以RequestConfig.Builder以及RequestConfigCallback有关。我们先看RequestConfig.Builder。

2.5 RequestConfig.Builder

看名字应该是和请求配置相关的类,

public static class Builder {//超时 private int socketTimeout;//公开方法public Builder setSocketTimeout(final int socketTimeout) {this.socketTimeout = socketTimeout;return this;}
}

可见,在Builder类中有超时的设置方法,现在就是找在哪可以设置超时了,我们进入RequestConfigCallback看看。

2.6、RestClientBuilder.RequestConfigCallback

RequestConfigCallback是RestClientBuilder的一个内部接口,也就是说我们要实现该接口。

/*** Callback used the default {@link RequestConfig} being set to the {@link CloseableHttpClient}* @see HttpClientBuilder#setDefaultRequestConfig*/
public interface RequestConfigCallback {//实现该方法,对builder超时进行设置RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder);
}

可以看到,接口唯一的方法是customizeRequestConfig(),参数是RequestConfig.Builder,返回值也是RequestConfig.Builder。也就是说,我们可以通过该方法覆写RequestConfig.Builder的超时设置并返回回去。

实现子类如下

//采用匿名类
RestClientBuilder.RequestConfigCallback test = new RestClientBuilder.RequestConfigCallback() {@Overridepublic RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder){requestConfigBuilder.setSocketTimeout(1000);return requestConfigBuilder;}
};//上述代码可简化成lamba表达式
RestClientBuilder.RequestConfigCallback requestConfigCallback = requestConfigBuilder -> requestConfigBuilder.setSocketTimeout(28_800_000);

现在就是缺如何设置RequestConfigCallback,看类注释,提示我们看HttpClientBuilder.setDefaultRequestConfig方法。

2.6、HttpClientBuilder.setDefaultRequestConfig

源码如下,可以看到是设置RequestConfigCallback的方法。

public RestClientBuilder setRequestConfigCallback(RequestConfigCallback requestConfigCallback) {Objects.requireNonNull(requestConfigCallback, "requestConfigCallback must not be null");this.requestConfigCallback = requestConfigCallback;return this;
}

3、总结

综上所述,解决思路

  • 实现RestClientBuilder.RequestConfigCallback,覆盖RequestConfig.Builder的超时设置
  • 通过HttpClientBuilder.setDefaultRequestConfig设置RestClientBuilder.RequestConfigCallback

4、Spring自动装配

Spring装配的RestHighLevelClient的两种解决方法都在spring自动装配的配置类RestClientAutoConfiguration中。我们来看看是如何导入并自动装配的

4.1、spring.factories

spring-boot-autoconfigure.jarspring.factoriesRestClientAutoConfiguration的导入,

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
...省略其他
org.springframework.boot.autoconfigure.elasticsearch.rest.RestClientAutoConfiguration,\

4.2、RestClientAutoConfiguration

RestClientAutoConfiguration又导入了其他的配置类,且该类的条件是类路径上有RestClient.class。也就是说,只要用了spring boot+elasticsearch-rest-client,就会开启自动配置。源码如下:

@Configuration(proxyBeanMethods = false)
//条件
@ConditionalOnClass(RestClient.class)
//属性配置相关
@EnableConfigurationProperties(RestClientProperties.class)
//真正的装配类,都是在里面
@Import({ RestClientConfigurations.RestClientBuilderConfiguration.class,RestClientConfigurations.RestHighLevelClientConfiguration.class,RestClientConfigurations.RestClientFallbackConfiguration.class })
public class RestClientAutoConfiguration {}

可以看见,Import的都是RestClientConfigurations的内部类,我们进入RestClientConfigurations看看。

4.3、RestClientConfigurations

RestClientConfigurations就是真正的配置类了,该类创建RestClientBuilder,并基于RestClientBuilder创建了RestHighLevelClient,有三个内部类:

  • RestClientBuilderConfiguration:创建RestClientBuilder,yml的配置项在此处解析,如host,time-out等
  • RestHighLevelClientConfiguration:基于builder创建RestHighLevelClient,需要有RestHighLevelClient.class
  • RestClientFallbackConfiguration:RestClient回调配置
4.3.1、RestClientBuilderConfiguration

该类是创建RestClientBuilder,其他配置类通过RestClientBuilder创建RestHighLevelClient。源码如下:

@Configuration(proxyBeanMethods = false)
static class RestClientBuilderConfiguration {@Bean@ConditionalOnMissingBean//条件,缺少则创建RestClientBuilder elasticsearchRestClientBuilder(RestClientProperties properties,ObjectProvider<RestClientBuilderCustomizer> builderCustomizers) {//配置的连接地址设置HttpHost[] hosts = properties.getUris().stream().map(HttpHost::create).toArray(HttpHost[]::new);RestClientBuilder builder = RestClient.builder(hosts);PropertyMapper map = PropertyMapper.get();map.from(properties::getUsername).whenHasText().to((username) -> {CredentialsProvider credentialsProvider = new BasicCredentialsProvider();Credentials credentials = new UsernamePasswordCredentials(properties.getUsername(),properties.getPassword());credentialsProvider.setCredentials(AuthScope.ANY, credentials);builder.setHttpClientConfigCallback((httpClientBuilder) -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider));});//读取yml配置文件的超时配置并设置builder.setRequestConfigCallback((requestConfigBuilder) -> {map.from(properties::getConnectionTimeout).whenNonNull().asInt(Duration::toMillis).to(requestConfigBuilder::setConnectTimeout);map.from(properties::getReadTimeout).whenNonNull().asInt(Duration::toMillis)//超时.to(requestConfigBuilder::setSocketTimeout);return requestConfigBuilder;});//自定义的bean,覆写配置builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));return builder;}}
4.3.2、RestHighLevelClientConfiguration

该类基于RestClientBuilder创建RestHighLevelClient,源码如下:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestHighLevelClient.class)//条件,
static class RestHighLevelClientConfiguration {//创建RestHighLevelClient@Bean@ConditionalOnMissingBeanRestHighLevelClient elasticsearchRestHighLevelClient(RestClientBuilder restClientBuilder) {return new RestHighLevelClient(restClientBuilder);}@Bean@ConditionalOnMissingBeanRestClient elasticsearchRestClient(RestClientBuilder builder,ObjectProvider<RestHighLevelClient> restHighLevelClient) {RestHighLevelClient client = restHighLevelClient.getIfUnique();if (client != null) {return client.getLowLevelClient();}return builder.build();}}

4.4 RestClientProperties

该类是配置文件的映射类,前缀是spring.elasticsearch.rest,我们可以看看有那些可以用的配置项:

@ConfigurationProperties(prefix = "spring.elasticsearch.rest")
public class RestClientProperties {/*** Comma-separated list of the Elasticsearch instances to use.*///默认地址private List<String> uris = new ArrayList<>(Collections.singletonList("http://localhost:9200"));/*** Credentials username.*/private String username;/*** Credentials password.*/private String password;/*** Connection timeout.默认1秒*/private Duration connectionTimeout = Duration.ofSeconds(1);/*** Read timeout.默认30秒*/private Duration readTimeout = Duration.ofSeconds(30);
}

Es 超时设置 high-level-client相关推荐

  1. go http.Get请求 http.Post请求 http.PostForm请求 Client 超时设置

    http中有Get/Post/PostForm方法 也可以通过http包中设置client 请求配置 ,然后通过client.Do方法实现请求 下demo中功能都实现,其中有详细说明: package ...

  2. php mysql 超时时间_php mysql超时设置方法

    php mysql超时设置方法,源码,参数,底层,层面,都是 php mysql超时设置方法 易采站长站,站长之家为您整理了php mysql超时设置方法的相关内容. php mysql超时设置方法: ...

  3. Socket编程实践(9) --套接字IO超时设置方法

    引:超时设置3种方案 1. alarm超时设置方法 //代码实现: 这种方式较少用 void sigHandlerForSigAlrm(int signo) {return ; }signal(SIG ...

  4. nginx中的超时设置,请求超时、响应等待超时等

    nginx比较强大,可以针对单个域名请求做出单个连接超时的配置. 比如些动态解释和静态解释可以根据业务的需求配置 proxy_connect_timeout :后端服务器连接的超时时间_发起握手等候响 ...

  5. nginx 的超时设置

    前言 我们在使用nginx做反向代理的时候,可能会遇到这个场景:后端正常的业务处理时间超过了nginx的超时时间,导致nginx主动返回504.为解决这个问题,我们网上搜索发现可以通过调整这几个参数来 ...

  6. restlet2.0学习——请求超时设置

    一般,我们在请求一个rest service的时候,总是希望可以设置一些超时的参数,这样便于控制,如果service一直没有响应,可以有所反馈. 在http client 的请求中有两种可以设置的超时 ...

  7. OkHttp3超时设置和超时异常捕获

    OkHttp3超时设置 已经不能在 OkHttp3中使用的方法 为了容错和更好的用户体验,必须为OkHttp设置超时. 上网找了半天,只找到下面的代码.注意它们不能在 OkHttp3中使用 publi ...

  8. C socket: 关于connect超时设置

    使用阻塞的socket, 可以设置读写超时, struct timeval tv_timeout; tv_timeout.tv_sec = 60; tv_timeout.tv_usec = 0; if ...

  9. java setsotimeout_HttpClient超时设置setConnectionTimeout和setSoTimeout

    http是基于TCP/IP进行通信的,tcp通过3次握手建立连接,并最终以4次挥手终止通信. 知乎上对三次握手和四次挥手有如下解释: 作者:知乎用户 链接:https://www.zhihu.com/ ...

最新文章

  1. 数据蒋堂 | 数据库的封闭性
  2. Elastic Stack简介和Elasticsearch基本介绍
  3. [跟我学中小企业架构部署]之八:备份服务器部署
  4. php调用ruby,ruby、javascript、php中的观察者模式实现代码
  5. c语言实验 正弦csdn,实验2 正弦波振荡器(LC振荡器和晶体振荡器)
  6. 为Autodesk Infrastructure Map Server(AIMS) Mobile Viewer创建自定义控件
  7. Windows移动开发(一)——登堂入室
  8. Mini 容器学习笔记10——方法注入
  9. 台达编码器型号含义_台达伺服电机命名规则
  10. 【转载】非常实用的chrome插件 IT人必备
  11. c# Directshow
  12. android 热更新 方案,与Android热更新方案Amigo的初次接触
  13. 解决电视盒子占用wifi带宽问题
  14. 斜杠‘/‘ 和反斜杠‘\‘
  15. 剑指 Offer 58 - II. 左旋转字符串
  16. 证明线性空间子空间的基可以扩充为整个空间的基
  17. BPC BADI开发注意事项
  18. 编写程序实现乐手弹奏乐器。乐手可以弹奏不同的乐器从而发出不同的声音。可以弹奏的乐器包括二胡、钢琴和琵琶。
  19. 【测控电路】三运放高共模抑制比放大电路
  20. android 调用相机拍照。适配到 Android 10

热门文章

  1. 【优麒麟 UbuntuKylin】他来了他来了!麒麟移动应用环境上线了!
  2. 多维度数据分析是什么?该怎么做?
  3. 百度地图--绘制自定义铁路线
  4. 超级鹰模拟登录古诗文网站
  5. 《introduction to information retrieval》信息检索学习笔记2 词项词汇和倒排记录表
  6. ORA-01436 与 层次查询CONNECT BY
  7. 还有人在质疑数据挖掘是泡沫吗?千万不要叶公好龙
  8. Newman运行集合排错
  9. 球球音响机器人怎么合成的_PS合成机器人教程
  10. 三菱触摸屏u盘上传和下载_Smart700 IE V3触摸屏怎样用U盘下载程序-工业支持中心-西门子中国...