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.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章