【发布时间】:2020-04-10 06:05:31
【问题描述】:
***更新 - 我发现了一篇有用的 StackOverflow 帖子,其中其他人遇到了类似的问题,即 Elasticsearch 的 Healthcheck 监视器失败 Springboot elastic search health management : ConnectException: Connection refused
Healthcheck 执行器似乎使用 Rest 客户端,然而,用于映射、获取索引等的 Elasticsearch 使用 RestHighLevelClient。我们有一个 @config 文件,其中包含 esPort、esHost 和 esSchema 的变量(即端口 9200、主机 localhost 和模式 http),代码如下,以及“ESClient.java”类的代码:
ESClientConfig.java 类
package com.cat.digital.globalsearch.configuration;
import com.cat.digital.globalsearch.component.ESClient;
import org.apache.http.HttpHost;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ESClientConfig {
@Value("${elasticSearch.host}")
private String esHost;
@Value("${elasticSearch.port}")
private int esPort;
@Value("${elasticSearch.scheme}")
private String esScheme;
@Bean
public ESClient esClient() {
return new ESClient( new HttpHost(esHost, esPort, esScheme));
}
}
ESClient.java类
package com.cat.digital.globalsearch.component;
import com.cat.digital.globalsearch.model.IndexDocument;
import org.apache.http.HttpHost;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.PutMappingRequest;
import java.io.IOException;
import java.util.List;
import static org.elasticsearch.client.RequestOptions.DEFAULT;
import static org.elasticsearch.common.xcontent.XContentType.JSON;
/**
* Wrapper around {@link RestHighLevelClient}
*/
public class ESClient {
private final RestClientBuilder builder;
private final RestHighLevelClient searchClient;
public ESClient(HttpHost... hosts) {
this.builder = RestClient.builder(hosts);
searchClient = new RestHighLevelClient(RestClient.builder(hosts));
}
/**
* @param index String represents index name in ES
* @return true if index exists, false if not
*/
public boolean hasIndex(String index) throws IOException {
final GetIndexRequest request = new GetIndexRequest(index);
try (RestHighLevelClient client = new RestHighLevelClient(builder)) {
return client.indices().exists(request, DEFAULT);
}
}
所以现在我认为与 Elasticsearch 的“连接被拒绝”可能是因为在开发环境中它试图使用 Rest 客户端并且不存在正确的连接参数。但这将如何解释 Healthcheck 监视器在本地正常工作? RestHighLevelClient 是否在本地使用?
我在 spring boot GitHub 上发布了一个问题,并在此处被引用。我会尽量让这件事变得简单,这样我就能得到一些帮助。它实际上很简单。
TL;DR
使用 Spring Boot 执行器为 Elasticsearch 服务创建自定义 Healthcheck 监控器
创建了 1 个名为“IndexExists”的自定义 Java 类(代码如下)
添加了 Application.yml 文件:rest.uri = ['our-dev-url-on-aws'] 属性
我有一个应用程序在本地和远程都可以正常工作,但是当使用 Spring Boot 添加自定义 Healthcheck 监视器来监视我的 Elasticsearch 服务时,我收到 Elasticsearch 的“连接被拒绝”,并且运行状况检查监视器最终失败。 AWS 上的负载均衡器尝试访问此端点,并且由于运行状况检查无法连接到 Elasticsearch,因此它返回状态:“DOWN”,负载均衡器开始创建新容器。查看 CloudWatch 日志时,这种情况会在无限循环中反复发生(负载均衡器尝试创建更多容器)。我想补充一下,这在本地工作得非常好 - 也就是说,当添加健康检查监视器并通过 POSTMAN 在执行器/健康端点上使用 HTTP GET 请求时,我得到了正确的 JSON 响应:
来自 /actuator/health 端点的本地 JSON 响应(GET 请求)
{
"status": "UP",
"details": {
"indexExists": {
"status": "UP",
"details": {
"index": "exists",
"value": "assets"
}
},
"diskSpace": {
"status": "UP",
"details": {
"total": 250790436864,
"free": 194987540480,
"threshold": 10485760
}
},
"elasticsearchRest": {
"status": "UP",
"details": {
"cluster_name": "elasticsearch",
"status": "yellow",
"timed_out": false,
"number_of_nodes": 1,
"number_of_data_nodes": 1,
"active_primary_shards": 7,
"active_shards": 7,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 5,
"delayed_unassigned_shards": 0,
"number_of_pending_tasks": 0,
"number_of_in_flight_fetch": 0,
"task_max_waiting_in_queue_millis": 0,
"active_shards_percent_as_number": 58.333333333333336
}
}
}
}
如您所见,Healthcheck 监视器在顶部返回 "details": { "indexExists": etc... } 部分,用于检查我的 Elasticsearch 索引是否映射到字符串 = "assets"。如果是,则返回“status”:“UP”。
但是,当将此代码推送到 Azure 中的构建管道时,我可以在开发环境中进行测试,这是我得到的 JSON 响应:
来自 /actuator/health 端点的 DEV JSON 响应(GET 请求)
{
"status": "DOWN",
"details": {
"indexExists": {
"status": "UP",
"details": {
"index": "exists",
"value": "assets"
}
},
"diskSpace": {
"status": "UP",
"details": {
"total": 16776032256,
"free": 9712218112,
"threshold": 10485760
}
},
"elasticsearchRest": {
"status": "DOWN",
"details": {
"error": "java.net.ConnectException: Connection refused"
}
}
}
}
我可以在我们的 AWS (Amazon Web Services) 集群上查看错误日志,它们看起来像这样:
我创建并添加到我们的代码库中的 java 类是 IndexExists.java。它实现了 HealthIndicator() 接口并使用 Spring Boot 中的执行器:
IndexExists.java 类
package com.cat.digital.globalsearch.component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
import com.cat.digital.globalsearch.data.Indices;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Component
public class IndexExists implements HealthIndicator {
private final ESClient esClient;
private static final Logger LOGGER = LoggerFactory.getLogger(IndexExists.class);
Map<String,String> map = new HashMap<>();
@Autowired
public IndexExists(ESClient esClient) {
this.esClient = esClient;
}
@Override
public Health health() {
try {
if (!esClient.hasIndex(Indices.INDEX_ASSETS)) {
return Health.down().withDetail("index", Indices.INDEX_ASSETS + " index does not exist").build();
}
} catch (IOException e) {
LOGGER.error("Error checking if Elasticsearch index {} exists , with exception", Indices.INDEX_ASSETS, e);
}
map.put("index","exists");
map.put("value", Indices.INDEX_ASSETS);
return Health.up().withDetails(map).build();
}
}
我不会发布 application.yml 的所有代码,但这里是我添加的部分。对于spring dev profile,我只添加了rest uri,其余代码已经存在:
management:
endpoint:
health:
show-details: always
spring:
profiles: dev
elasticSearch:
host: "aws-dev-url"
port: -1
scheme: https
rest:
uris: ["aws-dev-url"]
我希望信息不要太多!我真的需要帮助...如果有人需要更多信息,请告诉我。谢谢。
【问题讨论】:
标签: java spring amazon-web-services spring-boot elasticsearch