问题现象是: 在Springboot启动后,进行一次文档操作增删改查等,之后空闲大概不到十分钟,在进行文档操作时会抛出异常Connect Rest,抛出此次异常后再次进行文档操作又恢复了正常。感觉原因应该是第一次操作之后连接一直在空闲状态Elasticsearch端关闭了空闲了连接导致第二次操作发生了异常,因为此时elasticsearch-java产生的RestClient并不知道Elasticsearch已经关闭了连接,第三次操作文档时因为第二次连接发生了异常所以新建了连接,此时又恢复了正常。
环境:
- Elasticsearch8.10.4
- spring-boot-starter-data-elasticsearch 3.1.5
解决方案: 给RestClientBuilder的HttpAsyncClientBuilder属性设置保活策略
参考自:spring data elasticsearch: 设置保活策略|长时间不连接es,报错超时连接_setkeepalivestrategy-CSDN博客
这位大佬给出的方案对我的项目来说有些美中不足,因为我使用的是boot-starter,如果自己创建一个RestClient(es8以后使用elasticsearch-java,这位大佬使用的是RestHighLevelClient)的Bean,就无法完美适配spring-boot-starter-data-elasticsearch提供的参数配置。
通过阅读源码发现其实spring-boot-starter-data-elasticsearch提供了RestClientBuilder这个bean的扩展点RestClientBuilderCustomizer接口,实现该接口后可以在创建RestClientBuilder这个bean时定义一些属性,比如HttpAsyncClientBuilder。
源码位置
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestClientBuilderConfiguration#elasticsearchRestClientBuilder
我们可以自定义一个Bean实现RestClientBuilderCustomizer接口,来定义HttpAsyncClientBuilder的属性 代码如下:
/**
* Spring-data-elasticsearch-starter的回调,用于自定义RestClientBuilderBean的属性
* */
@Component
public class KeepAliveStrategyRestClientBuilderCustomizer implements RestClientBuilderCustomizer {
@Override
public void customize(RestClientBuilder builder) {}
/**
* 设置连接保活策略为1分钟
* */
@Override
public void customize(HttpAsyncClientBuilder builder) {
builder.setKeepAliveStrategy(new ConnectionKeepAliveStrategy() {
@Override
public long getKeepAliveDuration(HttpResponse httpResponse, HttpContext httpContext) {
return Duration.ofMinutes(1).toMillis();
}
});
}
}