1. 程式人生 > >ElasticSearch學習總結(五):底層索引控制

ElasticSearch學習總結(五):底層索引控制

本文主要總結底層索引控制的一些知識點

1. 底層儲存目錄(Store Directory)

該模組主要用來控制索引資料的讀寫方式,Lucene所有在磁碟上的操作都是通過store模組來處理的,目前系統中有4種store型別,預設情況下,Elasticsearch會更具操作環境選擇一個最佳的型別。4種類型如下

  1. fs
    預設的配置。將根據操作環境選擇最佳配置:

    • Windows 32bit上選擇simplefs
    • 其他32bit系統上選擇niofs
    • 64bit系統上選擇mmapfs。
  2. simplefs:最簡單的一種實現(基於Java中的RandomAccessFile),對於簡單的應用,該store型別足夠了,但是該種類型的瓶頸主要在多執行緒讀寫.對於負責的應用,效能會很糟糕。 在Elasticsearch中,通過使用基於NIO的store型別而不使用基於簡單檔案系統的store實現

  3. niofs:該store型別是基於java.nio包中的FileChannel類的實現,該型別允許多執行緒操作同一個檔案,在多執行緒訪問的時候,效能也不會下降。該型別不推薦在windows上使用(主要是因為java實現的bug)

  4. mmapfs:該型別通過將檔案對映到記憶體(mmap)的方式將索引索引分片儲存到檔案系統上。 記憶體對映會佔用程序中虛擬記憶體一部分的地址空間,佔用的大小等於對映檔案的大小。 在使用此課程之前,請確保您已經允許充足的虛擬地址空間。

型別的配置除了可以在elasticsearch.yml中配置,還可以在建立索引的時候指定,方式如下:

PUT /my_index
{
  "settings"
: { "index.store.type": "niofs" } }

2. 準實時提交/更新

一個理想的搜尋解決方案中,新索引的資料應該能立即搜尋到。ElasticSearch給人的第一印象彷彿就是如此工作的,即使是在多伺服器環境下,然而事實並非如此. 原因如下:

在索引期新文件會寫入索引段。索引段是獨立的Lucene索引,這意味著查詢是可以與索引並行的,只是不時會有新增的索引段被新增到可被搜尋的索引段集合之中。

一次提交併不足以保證新索引的資料能被搜尋到,這是因為Lucene使用了一個叫作Searcher的抽象類來執行索引的讀取。如果索引更新提交了,但Searcher例項並沒有重新開啟,那麼它覺察不到新索引段的加入。Searcher重新開啟的過程叫作重新整理

(refresh)。出於效能考慮,Lucene推遲了耗時的重新整理,因此它不會在每次新增一個文件(或批量增加文件)的時候重新整理,但Searcher會每秒重新整理一次。這種重新整理已經非常頻繁了,然而有很多應用卻需要更快的重新整理頻率。如果碰到這種狀況,要麼使用其他技術,要麼審視需求是否合理。

ElasticSearch提供了兩種機制來控制重新整理的頻率

  1. 臨時強制重新整理:
curl -XGET localhost:9200/test/refresh
  1. 配置檔案配置:配置elasticsearch.xml 中的index.refresh_inverval

重新整理操作是很耗資源的,因此重新整理間隔時間越長,索引速度越快。如果需要長時間高速建索引,並且在建索引結束之前暫不執行查詢,那麼可以考慮將index.refresh_interval引數值設定為-1,然後在建索引結束以後再將該引數恢復為初始值。

3. 事務日誌

Apache Lucene能保證索引的一致性,這非常棒,但是這並不能保證當往索引中寫資料失敗時不會損失資料(如磁碟空間不足、裝置損壞,或沒有足夠的檔案控制代碼供索引檔案使用)。另外,頻繁提交操作會導致嚴重的效能問題(因為每提交一次就會觸發一個索引段的建立操作,同時也可能觸發索引段的合併)。

ElasticSearch通過使用事務日誌(transaction log)來解決上面的問題,它能儲存所有的未提交的事務,而ElasticSearch會不時建立一個新的日誌檔案用於記錄每個事務的後續操作。當有錯誤發生時,就會檢查事務日誌,必要時會再次執行某些操作,以確保沒有丟失任何更改資訊。而且,事務日誌的相關操作都是自動完成的,使用者並不會意識到某個特定時刻觸發的更新提交。

事務日誌中的資訊與儲存介質之間的同步(同時清空事務日誌)稱為事務日誌重新整理(flushing)
請注意事務日誌重新整理與Searcher重新整理的區別。
- Searcher重新整理:為了搜尋到最新的文件
- 事務日誌重新整理:用來確保資料正確寫入了索引並清空了事務日誌。

事務日誌的重新整理行為是可以自定義的。以下引數既可以通過修改elasticsearch.yml檔案來配置,也可以通過索引配置更新API來更改。

  • index.translog.flush_threshold_period:該引數的預設值為30分鐘,它控制了強制自動事務日誌重新整理的時間間隔,即便是沒有新資料寫入。強制進行事務日誌重新整理通常會導致大量的I/O操作,因此當事務日誌涉及少量資料時,才更適合進行這項操作。

  • index.translog.flush_threshold_ops:該引數確定了一個最大運算元,即在上次事務日誌重新整理以後,當索引更改操作次數超過該引數值時,強制進行事務日誌重新整理操作,預設值為5000。

  • index.translog.flush_threshold_size:該引數確定了事務日誌的最大容量,當容量大於等於該引數值,就強制進行事務日誌重新整理操作,預設值為200MB。

  • index.translog.disable_flush:禁用事務日誌重新整理。儘管預設情況下事務日誌重新整理是可用的,但對它臨時性地禁用能帶來其他方面的便利。例如,向索引中匯入大量文件的時候。在向索引匯入大量資料時,禁止重新整理可以大幅提高索引的速度。但是請記住,當資料匯入完畢之後,要重新設定事務日誌重新整理相關引數。

3.1 準實時讀取

實時讀取操作從索引中讀取資料時,會先檢查事務日誌中是否有可用的新版本。如果近期索引沒有與事務日誌同步,那麼索引中的資料將會被忽略,事務日誌中最新版本的文件將會被返回。

4. 控制索引合併

頻繁的文件更改操作會導致大量的小索引段,索引段數量過多會帶來如下問題:

  • 搜尋效能越低
  • 耗費記憶體更多。
  • 刪除操作,並沒有物理上刪除,只是做了標記刪除操作
  • 檔案控制代碼開啟過多的問題。

段合併可以帶來以下好處:
- 當多個索引段合併為一個的時候,會減少索引段的數量並提高搜尋速度。
- 也會減少索引的容量(文件數),因為在段合併時會移除被標記為已刪除的那些文件。

5. 合併的策略

  • tiered合併策略:這是ElasticSearch的預設選項。它能合併大小相似的索引段,並考慮每層允許的索引段的最大個數。在索引期,該合併策略會計算索引中允許出現的索引段個數,該數值稱為閾值(budget)。如果正在構建的索引中的段數超過了閾值,該策略將先對索引段按容量降序排序(這裡考慮了被標記為已刪除的文件),然後再選擇一個成本最低的合併。合併成本的計算方法傾向於回收更多刪除文件和產生更小的索引段。

5.1 合併的排程

除了可以影響索引合併策略的行為之外,ElasticSearch還允許我們定製合併策略的執行方式。

  • 併發合併排程器(ConcurrentMergeScheduler):該排程器使用多執行緒執行索引合併操作,其具體過程是:每次開啟一個新執行緒直到執行緒數達到上限,當達到執行緒數上限時,必須開啟新執行緒(因為需要進行新的段合併),那麼所有索引操作將被掛起,直到至少一個索引合併操作完成。
    為了控制最大執行緒數,可以通過修改index.merge.scheduler.max_thread_count屬性來實現。一般來說,可以按如下公式來計算允許的最大執行緒數:
Math.max(1, Math.min(4, Runtime.getRuntime().availableProcessors() / 2))

6. I/O調節

段合併的計算量龐大, 而且還要吃掉大量磁碟 I/O。合併在後臺定期操作,因為他們可能要很長時間才能完成,尤其是比較大的段。這個通常來說都沒問題,因為大規模段合併的概率是很小的。

不過有時候合併會拖累寫入速率。如果這個真的發生了,Elasticsearch 會自動限制索引請求到單個執行緒裡。這個可以防止出現 段爆炸 問題,即數以百計的段在被合併之前就生成出來。如果 Elasticsearch 發現合併拖累索引了,它會會記錄一個宣告有 now throttling indexing 的 INFO 級別資訊。

預設值是 20 MB/s,對機械磁碟應該是個不錯的設定。如果你用的是 SSD,可以考慮提高到 100–200 MB/s。測試驗證對你的系統哪個值合適:

PUT /_cluster/settings
{
    "persistent" : {
        "indices.store.throttle.max_bytes_per_sec" : "100mb"
    }
}

如果你在做批量匯入,完全不在意搜尋,你可以徹底關掉合併限流。這樣讓你的索引速度跑到你磁碟允許的極限:

PUT /_cluster/settings
{
    "transient" : {
        "indices.store.throttle.type" : "none" 
    }
}

Elasticsearch中可以配置節點級別或是索引級別的throttle,可以配置的型別包括none(不做限制),merge(限制merge),all(限制所有操作),配置的策略包括max_bytes_per_sec.