Elasticsearch Dangling Indices知識梳理

背景

前段時間客戶根據(jù)看到的ES日志報了索引無法創(chuàng)建的Bug,研發(fā)工作完成差不多后,開始梳理前線客戶Bug,調(diào)研后才發(fā)現(xiàn)原來是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信息中可以得到兩點(diǎn)信息:

  • 存在Dangling indices
  • 因?yàn)橹孛膯栴},ES無法向正常的處理Dangling indices那樣,處理當(dāng)前的Dangling indices

結(jié)合ES集群重現(xiàn)上述問題的操作步驟:

  • 搭建1master與1data的ES集群
  • 創(chuàng)建索引(假定為my_index),并寫入少量數(shù)據(jù)
  • 使用cp將data節(jié)點(diǎn)的nodes/0/indices路徑下my_index的目錄拷貝走
  • 對my_index執(zhí)行DELETE操作(或手工刪除master、data節(jié)點(diǎn)的data目錄中的數(shù)據(jù),然后重啟master與data)
  • 重復(fù)第2步操作,并將原my_index目錄拷貝到data節(jié)點(diǎn)下的nodes/0/indices目錄中
  • 重啟data節(jié)點(diǎn)
  • 這時data節(jié)點(diǎn)就會報出上述WARN信息

Dangling Indices

Dangling indices(懸空索引)指數(shù)據(jù)存儲在一個或多個節(jié)點(diǎn)磁盤上但當(dāng)前集群的clusterMetaData中并不包含這些索引信息。ES數(shù)據(jù)節(jié)點(diǎn)的啟動會首次從dataPath路徑下加載這些索引數(shù)據(jù),然后master能夠獲取到這些索引數(shù)據(jù)。Dangling indices通常是由以下幾種情況產(chǎn)生的:

  • 當(dāng)有數(shù)據(jù)結(jié)點(diǎn)處于offline狀態(tài),而此時通過DELETE操作刪除索引,刪除的索引數(shù)大于集群設(shè)置的tombstones數(shù)量(默認(rèn)為500),然后該數(shù)據(jù)節(jié)點(diǎn)啟動并重新加入集群
    -- DELETE操作將索引信息從clusterMetaData中刪除,而索引的真實(shí)數(shù)據(jù)在磁盤中
  • 可能是因?yàn)樵技簛G失了其所有主節(jié)點(diǎn)的原因,原始集群中的某個節(jié)點(diǎn)添加到另一個集群中
    添加到另一個集群的節(jié)點(diǎn),數(shù)據(jù)真實(shí)存儲在節(jié)點(diǎn)中,但新集群的clusterMetaData中不包含這些索引數(shù)據(jù)的信息
  • 對于集群的數(shù)據(jù)節(jié)點(diǎn)來說,可能是從備份中還原了老的、舊的索引文件
  • 集群丟失了所有主節(jié)點(diǎn),并且從備份中還原了這些主節(jié)點(diǎn),但是備份中的主節(jié)點(diǎn)不包含這些索引信息
    -- 同樣是節(jié)點(diǎn)存儲著索引數(shù)據(jù),但主節(jié)點(diǎn)維護(hù)的clusterMetaData中不包含這些索引信息

分析源碼可知,ES對Dangling Indices的處理策略是首先會去尋找并判定數(shù)據(jù)節(jié)點(diǎn)中的哪些索引屬于Dangling狀態(tài),然后組裝好這些Indices,最后將這些Dangling Indices發(fā)送給master等待著后續(xù)的Allocation操作。上述的findNewDanglingIndices(...)函數(shù)主要職責(zé)就是尋找并判定處于Dangling狀態(tài)的索引,可以看到當(dāng)一個索引本身是Dangling Index,但在判定過程中發(fā)現(xiàn)clusterMetaData中已經(jīng)存在與當(dāng)前Dangling索引完全一樣名稱的索引時,則會報出WARN:can not be imported as a dangling index...;即盡管是Dangling indices,但因?yàn)榇嬖谂cclusterMetaData中重名的緣故,因此ES自身不能像處理正常Dangling indices那樣來處理此索引。ES會選擇放棄這類Dangling indices的處理

對于這些重名的Dangling indices,查閱了一些資料,發(fā)現(xiàn)并沒有比較好的方式來處理;ES官方討論區(qū)推薦的方式為要么刪除Dangling indices;要么是刪除ES中已經(jīng)存在的與Dangling狀態(tài)同名的索引,別的也沒有比較好的方式;

深想下這個問題,因?yàn)槭莄lusterMetaData中存在重名的indices,所以才導(dǎo)致ES無法正確的處理Dangling indices。如果能對已存在ES集群中的索引名稱進(jìn)行rename,規(guī)避重名的情況,那ES就能夠正確處理Dangling狀態(tài)的indices了。于是Google了indices rename的操作,包括clone、reindex、snapshot等主要實(shí)現(xiàn)方式(暫不限于ES的版本),通過這些操作對重名的索引更改名稱,然后ES就可以正常的處理Dangling indices了。
小結(jié)

總結(jié)下來,處理重名的Dangling indices的方式主要有如下三種:

  • 刪除存儲在磁盤上的Dangling indices(一定的數(shù)據(jù)丟失)
  • 刪除已存儲在ES中的重名索引(一定的數(shù)據(jù)丟失)
  • 對已存儲在ES中的索引進(jìn)行rename操作,然后由ES正常處理Dangling indices(操作上繁瑣一些)

其實(shí)最好的方式應(yīng)該是盡可能的規(guī)避這個問題的發(fā)生,通過調(diào)研客戶環(huán)境發(fā)現(xiàn)其ES集群非常不穩(wěn)定,經(jīng)常會出現(xiàn)節(jié)點(diǎn)卡死并帶有重啟的操作;所以對此處理的策略是依據(jù)處理的數(shù)據(jù)量做好ES集群的規(guī)劃,包括master、data節(jié)點(diǎn)的部署劃分、依據(jù)ES能力進(jìn)行正常的寫入與搜索等操作。盡可能減少或避免繁重的且會導(dǎo)致ES卡死的操作,進(jìn)而避免ES節(jié)點(diǎn)頻繁的重啟發(fā)生。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容