Elasticsearch Document寫入原理

Document寫入原理

一. Document寫入原理

ES爲了實現進實時搜索,在寫入Document時利用了Buffer(內存),OS Cache(系統緩存,屬於系統內存的一部分),Disk(磁盤)三種存儲方式,儘可能的提升搜索的能力。ES的底層lucene實現的,在 luncene中一個index會被分爲若干個數據段segment,每一個segment都會存放index的部分document。從流程上講,ES會先把一個index中的document分散存儲在若干個shard(指的是主分片)上,在shard中,使用若干個segment來存儲具體的數據。
ES寫入數據的流程大致如下:
在這裏插入圖片描述

  1. 客戶端發起請求(增、刪、改)到ES中。
  2. ES將本次請求要操作的document寫入到buffer中。ES爲了保證搜索的近實時(Near Real Time 簡稱 NRT),默認每秒刷新一次buffer,這個刷新時間間隔可以手動修改,也可以通過命令觸發buffer的刷新。建議刷新時間間隔設置在1秒左右,好處使在服務器宕機後,只會丟失1秒左右的數據。
POST /index_name/_refresh

PUT index_name
{
  "settings": {
    "number_of_shards": 5,
    "number_of_replicas": 1,
    "refresh_interval": "1s"
  }
}
  1. ES在將document寫入到緩存的同時,也會將本次操作的具體內容寫入到translog文件中,這份文件存在的意義在於即便ES宕機了,也能儘可能的減少丟失的數據(簡單來說,就是把translog中的記錄重新執行一遍),當然translog也不能保證數據絕對不丟失,其原因在第6點詳細的講出了。由於translog存儲在磁盤Disk中,因此爲了提高訪問效率,ES與translog文件之間會建立並保持一個長連接(不然每次訪問都要獲取和釋放文件流)。
  2. 步驟2中提到過ES每隔一段時間就會刷新buffer,這個刷新的動作會在內存中創建一個全新的index segment,並將buffer中的document數據全部到這個新的index segment中。值得注意的是,index segment同樣是文件,只不過我們目前訪問的是內存中的File(ES底層使用java開發,new File()後文件會被讀取到內存當中)。
    segment中存儲的是buffer指定時間間隔內接收到的document寫操作數據(因爲Disk與內存有速度差,爲了讓數據持久化落盤的速度適應數據寫入內存的速度,我們使用了buffer,index segment,比如數據寫入了10秒,默認每秒刷新一次buffer,則產生10個index segment,而來得及寫入Disk的index segment可能只有2個)。此外 ,index segment已經是新增數據被處理成倒排索引後的數據結果了。
  3. 在index segment被創建並寫入了來自buffer的數據後,ES會立刻將index segment對應的File寫入到系統緩存OS Cache中並打開,這樣就可以立刻爲客戶端提供最新數據的請求服務,而不必等待index semeng寫入到磁盤後,再打開index segment。畢竟IO操作是一個重量級的操作,非常費時,一定會影響ES的近實時搜索能力。
  4. 前面說了,translog中記錄的是ES操作的過程,萬一遇到系統宕機,在系統重啓後,ES會重新讀取磁盤Disk中保存的數據(一份份的 index segment文件)至系統緩存,接着讀取translog中的操作日誌,並逐條執行,以此來達到恢復數據的目的。ES默認每隔5秒執行一次translog文件的持久化。如果在持久化的過程中恰好ES在做document寫操作,那麼本次持久化操作將暫停,直到寫操作徹底完成後,才繼續執行。translog的持久化方式默認同步,如果修改成異步,那麼在translog持久化的過程中新執行的寫操作對應的日誌就會丟失,如果恰好此時ES所在的服務器宕機,那麼這段時間還沒來得及持久化到Disk,僅位於內存中index segment或OS Cache緩存中的數據便無法恢復,永久丟失。
PUT index_name
{
  "settings": {
    "number_of_shards": 5,
    "number_of_replicas": 1,
    "index.translog.durability" : "async",
    "index.translog.sync_interval" : "5s"
  }
}
  1. 隨着時間的推移,translog文件會不斷的增大,在內存中積壓的數量衆多的index segment file的文件流也在不斷的增大,當translog文件大到一定程度或默認30分鐘執行一次,ES會自動觸發commit操作。commit操作的具體內容有:
    1. 將buffer中的數據刷新到一個新的index segment中;
    2. 將index segment寫入到OS Cache並打開index segment爲搜索提供服務;
    3. 執行一個commit point操作,將OS Cache中所有的index segment標識記錄在這個commit point中,並持久化到系統磁盤Disk;
    4. commit point操作會觸發fsync操作(file sync),將內存中已經寫入數據的index segment落盤到Disk,持久化成文件。
    5. 清空本次持久化的index segment對應在translog中的日誌。
  2. 按照上述的流程來看,每1秒會生成一個index segment文件,每30分鐘會將index segment文件流持久化到磁盤,照這樣來看,磁盤中的index segment文件會非常多,從而需要處於開啓狀態的index segment也非常多,在執行搜索操作時,找到數據對應的index segment就會比較費時了。爲了解決這個問題,ES會自動的執行segment merge操作,merge時,被標記爲deleted狀態的document會被物理刪除。
    merge的大致流程如下:
    1. ES會選取一些大小相近的segment文件流,合併成一個大的segment文件流(注意: segment可能是尚未持久化到磁盤的segment file,也可能是已經持久化到磁盤的segment file)。
    2. 執行commit操作,在Disk中記錄commit point,這個commit point不僅包含新增的segment,還包含合併後,需要被刪除的segment源文件的標識。
    3. commit操作結束後,ES會將merge後的segment文件重新打開,爲搜索提供服務,而那些舊的需要被刪除的segment文件則進行關閉並物理刪除。

此外,ES在執行search搜索時,目標數據可能位於不同的index segment上,因此ES會掃描所有已經開打的index segment文件並找到目標數據。文件打開指的是將數據讀到了OS Cache系統緩存,而不是內存中。

對index執行document的刪除和更新操作都不會立刻生效,而是標記成deleted狀態。當ES空閒(比如每隔30分鐘執行一次commit)或Disk存儲空間不足,ES就會物理刪除這些待刪除的數據。(猜測在內存不足時,也會執行刪除操作,因爲總不能讓尚未落盤的index segment大量的佔用內存吧)

在buffer數據寫入到segment的同時,會生成一個.del文件專門記錄哪一個index segment中哪一條document是deleted狀態(在merge後,這個.del文件會被更新)。因此ES搜索時,如果在多個index segment中查到了不同版本(version)的相同id值的document時,會根據.del文件中的記錄來繼續過濾,保證搜索結果的唯一性和正確性(比如segment1中包含一條document version=1,對應新增狀態;而segment2中包含相同id的document version=2,對應更新狀態。由於後者的版本號更新,因此在.del中,version1被視作舊document,會被標記成deleted狀態,從而在搜索時就會得到segment2中包含的version=2的數據了)。

注意:

  1. buffer和尚未寫入系統緩存的index segment(就是一段倒排索引)存儲在堆內存,受jvm參數控制。
  2. 系統緩存 OScache在這裏可以被看做是"文件系統緩存",用於緩存打開後的segment file(段文件),存儲在非堆內存,受操作系統控制。

非堆內存越大,能夠打開並緩存的segment file(段文件)就越多,搜索和聚合時,能夠直接從內存中獲取的熱數據也就越多(不需要通過IO,在磁盤中找到尚未打開的segment file,讀取文件內容)。

搜索數據時,首先在OS Cache中進行搜索,如果找不到數據,則在磁盤中找到對應的index segment文件並打開,讀取數據至堆內存中(ES由java開發,因此一定是讀取到堆內存,而不是OS Cache),接着,在堆內存中對數據進行聚合、排序等操作,最後把數據返回給協調節點,最終交給調用方。此外,新讀取到堆內存的segment file會被Lucense緩存至OS Cache中。

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