项目场景:

项目使用了ElasticSearch【后续简称Es】,配置了Es的相关配置,通过spring的健康检查端点判断服务运行情况。项目未通过reactor的方式使用Es。


问题描述:

系统配置文件配置如下:

​​spring:
  elasticsearch:
    rest:
      uris: http://xxxx:9200,http://xxxx:9200,http://xxxx:9200
      username: elastic
      password: ${pwd.elastic}

调用/actuator/health,发现状态为DOWN。控制台报错如下:

2021-06-23 11:32:32.827  WARN [] 30680 --- [ctor-http-nio-2] a.e.ElasticsearchReactiveHealthIndicator : Elasticsearch health check failed

org.springframework.data.elasticsearch.client.NoReachableHostException: Host 'localhost:9200' not reachable. Cluster state is offline.
    at org.springframework.data.elasticsearch.client.reactive.SingleNodeHostProvider.lambda$null$4(SingleNodeHostProvider.java:106)

原因分析:

从报错上看,这个健康检查明显使用的是响应式的健康检查。

通过debug发现host是localhost,并非配置文件中配置的地址:

client中的host配置是通过下面的配置进行配置的:

spring:
  data:
    elasticsearch:
      client:
        reactive:
          endpoints: http://xxxx:9200,http://xxxx:9200,http://xxxx:9200
          username: elastic
          password: ${pwd.elastic}

配置上之后可以解决控制台报错,但是调用/actuator/health 会卡死。

继续排查:

从堆栈上看出这个bean是通过ElasticSearchReactiveHealthContributorAutoConfiguration 注入的:

package org.springframework.boot.actuate.autoconfigure.elasticsearch;

import java.util.Map;
import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthContributorConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
import org.springframework.boot.actuate.elasticsearch.ElasticsearchReactiveHealthIndicator;
import org.springframework.boot.actuate.health.ReactiveHealthContributor;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRestClientAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
import reactor.core.publisher.Flux;

@Configuration(
  proxyBeanMethods = false
)
@ConditionalOnClass({ReactiveElasticsearchClient.class, Flux.class})
@ConditionalOnBean({ReactiveElasticsearchClient.class})
@ConditionalOnEnabledHealthIndicator("elasticsearch")
@AutoConfigureAfter({ReactiveElasticsearchRestClientAutoConfiguration.class})
public class ElasticSearchReactiveHealthContributorAutoConfiguration extends CompositeReactiveHealthContributorConfiguration<ElasticsearchReactiveHealthIndicator, ReactiveElasticsearchClient> {
  public ElasticSearchReactiveHealthContributorAutoConfiguration() {
  }

  @Bean
  @ConditionalOnMissingBean(
    name = {"elasticsearchHealthIndicator", "elasticsearchHealthContributor"}
  )
  public ReactiveHealthContributor elasticsearchHealthContributor(Map<String, ReactiveElasticsearchClient> clients) {
    return (ReactiveHealthContributor)this.createContributor(clients);
  }
}

也就是项目只要依赖的Flux相关的的内容就会创建这个bean。同时项目中也有:

org.springframework.boot.actuate.autoconfigure.elasticsearch.ElasticSearchRestHealthContributorAutoConfiguration

这里会注入rest方式的健康检查bean。

两者同时存在时,健康检查取用了响应式的检查类。


解决方案:

从上面的分析可以看出解决办法有两个:

方案1、排除Flux相关依赖;

方案2、排除ElasticSearchReactiveHealthContributorAutoConfiguration。

我这采用的第二种,在启动类中排除该依赖即可:

@SpringBootApplication(exclude=ElasticSearchReactiveHealthContributorAutoConfiguration.class)

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐