ElasticSearch 问题分析:No data nodes with HTTP-enabled available

Posted yuzjang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ElasticSearch 问题分析:No data nodes with HTTP-enabled available相关的知识,希望对你有一定的参考价值。

环境:ES-5.4.0版本,部署方式:3master+2client+3datanode

说明:datanode和client都配置了http.enabled: false,程序在写数据时报错:No data nodes with HTTP-enabled available

源码分析:

public static void filterNonDataNodesIfNeeded(Settings settings, Log log) {
    if (!settings.getNodesDataOnly()) {
        return;
    }

    RestClient bootstrap = new RestClient(settings);
    try  {
        String message = "No data nodes with HTTP-enabled available";
        List<NodeInfo> dataNodes = bootstrap.getHttpDataNodes();
    // 找不到dataNodes就会报错 if (dataNodes.isEmpty()) { throw new EsHadoopIllegalArgumentException(message); } ... } finally { bootstrap.close(); } }

接下来看看RestClient.getHttpDataNodes()方法的取值逻辑

public List<NodeInfo> getHttpDataNodes() {
    List<NodeInfo> nodes = getHttpNodes(false);
  // 遍历上面获取到的节点 Iterator<NodeInfo> it = nodes.iterator(); while (it.hasNext()) { NodeInfo node = it.next();
    // 如果不是数据节点,则移除 if (!node.isData()) { it.remove(); } } return nodes; }
// 获取http节点_nodes/http public List<NodeInfo> getHttpNodes(boolean clientNodeOnly) {
  // 通过es接口“_nodes/http”来获取nodes的信息 Map<String, Map<String, Object>> nodesData = get("_nodes/http", "nodes"); List<NodeInfo> nodes = new ArrayList<NodeInfo>(); for (Entry<String, Map<String, Object>> entry : nodesData.entrySet()) { NodeInfo node = new NodeInfo(entry.getKey(), entry.getValue());
    // 如果不是查找client节点,则只要节点运行网络访问就可以add了;如果查找client节点,则还要通过isClient验证才能add if (node.hasHttp() && (!clientNodeOnly || node.isClient())) { nodes.add(node); } } return nodes; }

 最后再来看看node.hasHttp(),isClient(),isData()的方法

    private final String id;
    private final String name;
    private final String host;
    private final String ip;
    private final String publishAddress;
    private final boolean hasHttp;
    private final boolean isClient;
    private final boolean isData;
    private final boolean isIngest;

    public NodeInfo(String id, Map<String, Object> map) {
        this.id = id;
        EsMajorVersion version = EsMajorVersion.parse((String) map.get("version"));
        this.name = (String) map.get("name");
        this.host = (String) map.get("host");
        this.ip = (String) map.get("ip");
    // 5.0以下版本的分支 if (version.before(EsMajorVersion.V_5_X)) { Map<String, Object> attributes = (Map<String, Object>) map.get("attributes"); if (attributes == null) { this.isClient = false; this.isData = true; } else { String data = (String) attributes.get("data"); this.isClient = data == null ? true : !Boolean.parseBoolean(data); this.isData = data == null ? true : Boolean.parseBoolean(data); } this.isIngest = false;
    // 5.0版本以上的分支 } else { List<String> roles = (List<String>) map.get("roles");
      // 如果roles列表中不包含"data",则此节点是client this.isClient = roles.contains("data") == false;
      // 如果roles列表中包含"data",则此节点是data this.isData = roles.contains("data");
      // 如果roles列表中包含"ingest",则此节点是ingest this.isIngest = roles.contains("ingest"); } Map<String, Object> httpMap = (Map<String, Object>) map.get("http");
    // 如果节点数据中包含key:http if (httpMap != null) { String addr = (String) httpMap.get("publish_address");
      // 如果http数据中包含key:publish_address if (addr != null) { StringUtils.IpAndPort ipAndPort = StringUtils.parseIpAddress(addr); this.publishAddress = ipAndPort.ip + ":" + ipAndPort.port;
        // 则此节点可以提供http服务,即:http.enabled: true this.hasHttp = true; } else { this.publishAddress = null; this.hasHttp = false; } } else { this.publishAddress = null; this.hasHttp = false; } }

 从上面的源码分析可以得出:如果一个data节点不配置http.enabled:true,则此节点不会被getHttpDataNodes()方法搜索到,那么就会直接抛出异常:No data nodes with HTTP-enabled available

解决的方法无非两种:

第一:数据节点配置 http.enabled:true

第二:绕过filterNonDataNodesIfNeeded()校验,需要settings.getNodesDataOnly()返回false;看下面源码可知,默认es.nodes.data.only是true,在客户端中将其设置为false即可。

/** Clients only */
String ES_NODES_CLIENT_ONLY = "es.nodes.client.only";
String ES_NODES_CLIENT_ONLY_DEFAULT = "false";

/** Data only */
String ES_NODES_DATA_ONLY = "es.nodes.data.only";
String ES_NODES_DATA_ONLY_DEFAULT = "true";

/** Ingest only */
String ES_NODES_INGEST_ONLY = "es.nodes.ingest.only";
String ES_NODES_INGEST_ONLY_DEFAULT = "false";

/** WAN only */
String ES_NODES_WAN_ONLY = "es.nodes.wan.only";
String ES_NODES_WAN_ONLY_DEFAULT = "false";

...

public boolean getNodesDataOnly() {
    // by default, if not set, return a value compatible with the other settings
  // 默认es.nodes.data.only是true,在客户端中将其设置为false即可 return Booleans.parseBoolean(getProperty(ES_NODES_DATA_ONLY), !getNodesWANOnly() && !getNodesClientOnly() && !getNodesIngestOnly()); } public boolean getNodesIngestOnly() { return Booleans.parseBoolean(getProperty(ES_NODES_INGEST_ONLY, ES_NODES_INGEST_ONLY_DEFAULT)); } public boolean getNodesClientOnly() { return Booleans.parseBoolean(getProperty(ES_NODES_CLIENT_ONLY, ES_NODES_CLIENT_ONLY_DEFAULT)); } public boolean getNodesWANOnly() { return Booleans.parseBoolean(getProperty(ES_NODES_WAN_ONLY, ES_NODES_WAN_ONLY_DEFAULT)); }

 

以上是关于ElasticSearch 问题分析:No data nodes with HTTP-enabled available的主要内容,如果未能解决你的问题,请参考以下文章

关于elasticsearch node 节点不可用的故障分析

elasticsearch类型转换

将 dat 文件导入 R

Docker安装elasticsearch

Elasticsearch 特殊字符搜索

SpingBoot:整合Elasticsearch7.2.0