美文网首页
Elasticsearch Dangling Indices知识

Elasticsearch Dangling Indices知识

作者: 汤尼房 | 来源:发表于2020-10-21 22:00 被阅读0次
    背景

    前段时间客户根据看到的ES日志报了索引无法创建的Bug,研发工作完成差不多后,开始梳理前线客户Bug,调研后才发现原来是Dangling索引的问题;这篇文档算是对Dangling Indices知识的简短梳理。ES(5.6.4)日志的记录如下:

    [2020-09-17T01:51:05,715][WARN ][o.e.g.DanglingIndicesState] [elasticsearch1] [[filebeat-2020.08.11/Uwim4o6nREed8_It7vBQ7A]] can not be imported as a dangling index, as index with same name already exists in cluster metadata
    

    上述WARN信息,来源于ES的DanglingIndicesState类的findNewDanglingIndices(...)方法,如下:

    /**
     * Finds new dangling indices by iterating over the indices and trying to find indices
     * that have state on disk, but are not part of the provided meta data, or not detected
     * as dangled already.
     */
    Map<Index, IndexMetaData> findNewDanglingIndices(final MetaData metaData) {
        final Set<String> excludeIndexPathIds = new HashSet<>(metaData.indices().size() + danglingIndices.size());
        for (ObjectCursor<IndexMetaData> cursor : metaData.indices().values()) {
            excludeIndexPathIds.add(cursor.value.getIndex().getUUID());
        }
        excludeIndexPathIds.addAll(danglingIndices.keySet().stream().map(Index::getUUID).collect(Collectors.toList()));
        try {
            final List<IndexMetaData> indexMetaDataList = metaStateService.loadIndicesStates(excludeIndexPathIds::contains);
            Map<Index, IndexMetaData> newIndices = new HashMap<>(indexMetaDataList.size());
            final IndexGraveyard graveyard = metaData.indexGraveyard();
            for (IndexMetaData indexMetaData : indexMetaDataList) {
                if (metaData.hasIndex(indexMetaData.getIndex().getName())) {
                    logger.warn("[{}] can not be imported as a dangling index, as index with same name already exists in cluster metadata",
                        indexMetaData.getIndex());
                } else if (graveyard.containsIndex(indexMetaData.getIndex())) {
                    logger.warn("[{}] can not be imported as a dangling index, as an index with the same name and UUID exist in the " +
                        "index tombstones.  This situation is likely caused by copying over the data directory for an index " +
                        "that was previously deleted.", indexMetaData.getIndex());
                } else {
                    logger.info("[{}] dangling index exists on local file system, but not in cluster metadata, " +
                        "auto import to cluster state", indexMetaData.getIndex());
                    newIndices.put(indexMetaData.getIndex(), indexMetaData);
                }
            }
            return newIndices;
        } catch (IOException e) {
            logger.warn("failed to list dangling indices", e);
            return emptyMap();
        }
    }
    

    从WARN信息中可以得到两点信息:

    • 存在Dangling indices
    • 因为重名的问题,ES无法向正常的处理Dangling indices那样,处理当前的Dangling indices

    结合ES集群重现上述问题的操作步骤:

    • 搭建1master与1data的ES集群
    • 创建索引(假定为my_index),并写入少量数据
    • 使用cp将data节点的nodes/0/indices路径下my_index的目录拷贝走
    • 对my_index执行DELETE操作(或手工删除master、data节点的data目录中的数据,然后重启master与data)
    • 重复第2步操作,并将原my_index目录拷贝到data节点下的nodes/0/indices目录中
    • 重启data节点
    • 这时data节点就会报出上述WARN信息

    Dangling Indices

    Dangling indices(悬空索引)指数据存储在一个或多个节点磁盘上但当前集群的clusterMetaData中并不包含这些索引信息。ES数据节点的启动会首次从dataPath路径下加载这些索引数据,然后master能够获取到这些索引数据。Dangling indices通常是由以下几种情况产生的:

    • 当有数据结点处于offline状态,而此时通过DELETE操作删除索引,删除的索引数大于集群设置的tombstones数量(默认为500),然后该数据节点启动并重新加入集群
      -- DELETE操作将索引信息从clusterMetaData中删除,而索引的真实数据在磁盘中
    • 可能是因为原始集群丢失了其所有主节点的原因,原始集群中的某个节点添加到另一个集群中
      添加到另一个集群的节点,数据真实存储在节点中,但新集群的clusterMetaData中不包含这些索引数据的信息
    • 对于集群的数据节点来说,可能是从备份中还原了老的、旧的索引文件
    • 集群丢失了所有主节点,并且从备份中还原了这些主节点,但是备份中的主节点不包含这些索引信息
      -- 同样是节点存储着索引数据,但主节点维护的clusterMetaData中不包含这些索引信息

    分析源码可知,ES对Dangling Indices的处理策略是首先会去寻找并判定数据节点中的哪些索引属于Dangling状态,然后组装好这些Indices,最后将这些Dangling Indices发送给master等待着后续的Allocation操作。上述的findNewDanglingIndices(...)函数主要职责就是寻找并判定处于Dangling状态的索引,可以看到当一个索引本身是Dangling Index,但在判定过程中发现clusterMetaData中已经存在与当前Dangling索引完全一样名称的索引时,则会报出WARN:can not be imported as a dangling index...;即尽管是Dangling indices,但因为存在与clusterMetaData中重名的缘故,因此ES自身不能像处理正常Dangling indices那样来处理此索引。ES会选择放弃这类Dangling indices的处理

    对于这些重名的Dangling indices,查阅了一些资料,发现并没有比较好的方式来处理;ES官方讨论区推荐的方式为要么删除Dangling indices;要么是删除ES中已经存在的与Dangling状态同名的索引,别的也没有比较好的方式; 深想下这个问题,因为是clusterMetaData中存在重名的indices,所以才导致ES无法正确的处理Dangling indices。如果能对已存在ES集群中的索引名称进行rename,规避重名的情况,那ES就能够正确处理Dangling状态的indices了。于是Google了indices rename的操作,包括clone、reindex、snapshot等主要实现方式(暂不限于ES的版本),通过这些操作对重名的索引更改名称,然后ES就可以正常的处理Dangling indices了。
    小结

    总结下来,处理重名的Dangling indices的方式主要有如下三种:

    • 删除存储在磁盘上的Dangling indices(一定的数据丢失)
    • 删除已存储在ES中的重名索引(一定的数据丢失)
    • 对已存储在ES中的索引进行rename操作,然后由ES正常处理Dangling indices(操作上繁琐一些)

    其实最好的方式应该是尽可能的规避这个问题的发生,通过调研客户环境发现其ES集群非常不稳定,经常会出现节点卡死并带有重启的操作;所以对此处理的策略是依据处理的数据量做好ES集群的规划,包括master、data节点的部署划分、依据ES能力进行正常的写入与搜索等操作。尽可能减少或避免繁重的且会导致ES卡死的操作,进而避免ES节点频繁的重启发生。

    相关文章

      网友评论

          本文标题:Elasticsearch Dangling Indices知识

          本文链接:https://www.haomeiwen.com/subject/mgqymktx.html