Elasticsearch 架構原理


為什么要學習架構?

Elasticsearch的一些架構設計,對我們做性能調優、故障處理,具有非常重要的影響。下面將從Elasticsearch的准實時索引的實現、自動發現、rounting和replica的讀寫過程,shard的allocate控制

使文本可以被搜索?

在傳統的數據庫中,一個字段存一個值,但是這對於全文搜索是不足的。想要讓文本中的而每個單詞都可以被搜索,這意味着數據庫需要多個值。

支持一個字段多個值的最佳數據結構是倒排索引。倒排索引包含了出現在所有文檔中唯一的值或或詞的有序列表,以及每個詞所屬的文檔列表。

倒排索引存儲了比包含一個term的文檔列表多地多的信息,它可能包含每一個term的文檔數量,一個term出現在制定文檔中的頻次,每個文檔中term的順序,每個文檔的長度,所有文檔的平均長度等等。這些統計信息讓Elasticsearch知道哪些term更重要,哪些文檔更重要,也就是相關性。

在全文搜索的早些時候,會為整個文檔集合建立一個大索引,並且寫入磁盤。只有新索引准備好了它就會替代舊肚餓索引,最近的修改可以被檢索。

不可變性

寫入磁盤的倒排索引是不可變的,它有如下好處:

 

  • 不需要鎖。如果從來不需要跟新一個索引,就不必擔心多個程序見同時嘗試修改。
  • 一旦索引被讀入文件系統的緩存,它就一直在那兒,因為不會改變。只要文件系統緩存有足夠的空間,大部分的讀會直接訪問內存而不是磁盤。這有助於性能的提升。
  • 在索引的聲明周期內,所有的其他緩存都可用。他們不需要再每次數據變化了都重建,因此數據不會變。
  • 寫入單個大的倒排索引,可以壓縮數據,較少的磁盤IO和需要緩存索引的大小。

當然,不可變的索引有它的缺點,首先是它不可變。如果想要搜索一個新文檔,必須重建整個索引。這不僅限制了一個索引所能裝下的數據,還有一個索引可以被更新的頻次。

 

准實時索引的實現?

本文主要介紹Elasticsearch的准實時索引的實現,至於基於Lucene的倒排索引將不在這里介紹,有興趣的讀者可以去Lucene的相關文章,或者閱讀《Lucene in Action》等書籍。下面將介紹Elasticsearch索引流程中發生的具體操作,重點在於其中的segment、buffer和translog三部分對性能方面的影響。

1、動態更新的Lucnee索引

要做到實時跟新條件下數據的可用和可靠,就需要在倒排索引的基礎上,再做一系列更高級的處理。總結一下Lucene的處理辦法:新收到的數據寫入新的索引文件里。Lucene把每次生成的倒排索引,叫做一個段(segment)。然后另外使用一個commit文件,記錄索引內的所有segment。而生成segment的數據來源,則是內存中的buffer,也就是說,動態跟新過后過程如下:1)當前磁盤上有三個segement可用,同時有一個commit文件記錄當前的segment2)新收到的數據進入內存buffer,索引狀態如下所示。3)buffer刷到磁盤,生成一個新的segment,commit文件同步跟新。這樣可以完成跟新,也產生了幾個問題:1、每次一有數據就刷新到磁盤,會增大對磁盤的操作2、刷新到磁盤的時間占據很大一部分時間3、如果刷新的過程中刷新失敗應該怎么控制呢?

2、刪除和更新

segment是不可變的,所以文檔即不能從舊的段中刪除,舊的段也不能更新以反映文檔最新的文本。相反,每一個提交點包括一個.del文件,包含了段上已經被刪除的文檔當一個文檔被刪除,它是實際上只是在.del文件中被標記刪除,亦然可以匹配查詢,但最終返回之前會被從結果中刪除。文檔的跟新操作是類似的:當一個文檔被更新,舊版本的文檔被標記為刪除,新版本的文檔在新的段中索引。也許該文檔的不同版本都會匹配一個查詢,但是老版本會從結果中刪除。

3、利用磁盤緩存實現的准實時檢索

既然涉及到磁盤,那么一個不可避免的問題就來了:磁盤太慢了!對我們要求的實時性很高的服務來說,這種處理還不夠。所以,在剛剛第3步的處理中,還有一個中間狀態:1)內存buffer生成一個新的segment,刷到文件系統緩存中,Lucene即可檢索到這個新的segment,索引狀態如圖所示。2)文件系統緩存真正同步到磁盤上,commit文件跟新。刷到文件系統緩存中這個步驟,Elasticsearch默認1s的時間間隔,這也就是說相當於是實時搜索的,Elasticsearch也提供了單獨的/_reflush接口,用戶如果對1s間隔還是不太滿意,可以主動調用接口來保證搜索可見。

POST /_refresh <1>POST /blogs/_refresh <2>
  • <1> refresh所有索引
  • <2> 只refresh 索引blogs

一般來說我們會通過/_settings接口或者定制template的方式,加大refresh_interval參數:

PUT /my_logs/_settings{ "refresh_interval": -1 } <1>PUT /my_logs/_settings{ "refresh_interval": "1s" } <2>
  • <1> 禁用所有自動refresh
  • <2> 每秒自動refresh

 

4、translog提供的磁盤同步控制

既然refresh只是寫到文件系統緩存中,那么最后一步寫到實際磁盤又是由什么來控制的呢?如果這期間發生主機錯誤、硬盤故障等異常情況,數據會不會丟失?這里,其實Elasticsearch提供了另一個機制來控制。Elasticsearch也把數據寫入到內存buffer的同時,其實還另外記錄了一個treanslog的日志。也就是說,在內存數據進入到buffer這一步驟時,其實還另外記錄了一個translog記錄。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM