【Elasticsearch學習】之一圖讀懂文檔索引全過程

ES索引過程詳解:java

1.客戶端發送索引請求。node

  客戶端向ES節點發送索引請求,以RestClient客戶端發起請求爲例:算法

  ES提供了Java High Level REST Client,用戶能夠經過RestClient發送請求:緩存

  RestClient restClient = RestClient.builder(
            new HttpHost("127.0.0.1", 9200, "http"),
            new HttpHost("127.0.0.2", 9200, "http")
           ).build();

  其中127.0.0.1,127.0.0.1是ES中的節點,ES在接受請求時,充當coordinate node節點的角色,若是設置有專用coorinate node則應該將接受客戶端請求的節點設置爲該專用節點,負責請求的接受和轉發。在RestClient中使用round-robin輪詢算法,進行發送節點的選取。app

2.參數檢查學習

  對請求中的參數進行檢查,檢查參數是否合法,不合法的參數直接返回失敗給客戶端。優化

3.數據預處理ui

  若是請求指定了pipeline參數,則對數據進行預處理,數據預處理的節點爲Ingest Node,若是接受請求的節點不具備數據處理能力,則轉發給其餘能處理的節點。spa

  在Ingest Node上有定義好的處理數據的Pipeline,Pipeline中有一組定義好的Processor,每一個Processor分別具備不一樣的處理功能,ES提供了一些內置的Processor,如:split、join、set 、script等,同時也支持經過插件的方式,實現自定義的Processor。數據通過Pipeline處理完畢後繼續進行下一步操做。插件

4.判斷索引是否存在

  判斷索引是否存在。若是索引不存在,則判斷是否可以自動建立,能夠經過action.auto_create_index設置可否自動建立索引;若是節點支持Dynamic Mapping,寫入文檔時,若是字段還沒有在mapping中定義,則會根據索引文檔信息推算字段的類型,但並不能徹底推算正確。

  配置:Dynamic:true時,文檔有新增字段的時候,索引的mapping也會同步更新。

     Dynamic:false時,索引的mapping不會被更新,新增字段沒法被索引到。

     Dynamic:strict時,索引有新增字段時,將會報錯。

  注:生產環境儘可能避免使用Dynamic mapping,以避免過多字段致使cluster state佔用過多。

5.建立索引

  建立索引請求被髮送到Master節點,由Master節點負責進行索引的建立,索引建立成功後,Master節點會更新集羣狀態clusterstate,更新完畢後將索引建立的狀況返回給Coordinate節點,收到Master節點返回的全部建立索引的響應後,進入下一流程。

6.請求預處理

  1)獲取集羣狀態信息,判斷集羣是否正常;
  2)從集羣狀態中獲取對應索引的元信息,從元信息中獲取索引的mapping、version、等信息,從請求中解析routing、id信息,若是請求沒有指定文檔的id,則會生成一個UUID做爲文檔的id。
7.路由計算
  根據請求的routing、id信息計算文檔應該被索引到哪一個分配,計算公式:
shard_num = hash(_routing) % num_primary_shards
  _routing默認值爲文檔id,num_primary_shards是主分片個數,因此從算法中便可以看出索引的主分片個數一旦指定便沒法修改,由於文檔利用主分片的個數來進行定位。當使用自定義_routing或者id時,按照上面的公式計算,數據可能會大量彙集於某些分配,形成數據分佈不均衡,因此ES提供了 routing_partition_size參數,routing_partition_size越大,數據的分佈越均勻。分片的計算公式變爲:
shard_num = (hash(_routing) + hash(_id) % routing_partition_size) % num_primary_shards
  定位到shard序號後,還須要定位shard所屬的數據節點;從集羣狀態的內容路由表獲取主分片所在的節點,並將請求轉發至節點。須要注意的是shard到數據節點的映射關係不是固定的,當檢測到數據分佈不均勻、新節點加入或者節點宕掉等會進行shard從新分配。
8.主分片索引文檔
  當主分片所在節點接受到請求後,節點開始進行本節點的文檔寫入,文檔寫入過程以下:
  1)文檔寫入時,不會直接寫入到磁盤中,而是先將文檔寫入到Index Buffer內存空間中,到必定的時間,Index Buffer會Refresh把內存中的文檔寫入Segment中。當文檔在Index Buffer中時,是沒法被查詢到的,這就是ES不是實時搜索,而是近實時搜索的緣由。
  2)由於文檔寫入時,先寫入到內存中,當文檔落盤以前,節點出現故障重啓、宕機等,會形成內存中的數據丟失,因此索引寫入的同時會同步向Transaction Log寫入操做內容。
  3)每隔固定的時間間隔ES會將Index Buffer中的文檔寫入到Segment中,這個寫入的過程叫作Refresh,Refresh的時間能夠經過index.refresh_interval,默認狀況下爲1秒。
  4)寫入到Segment中並不表明文檔已經落盤,由於Segment寫入磁盤的過程相對耗時,Refresh時會先將Segment寫入緩存,開放查詢,也就是說當文檔寫入Segment後就能夠被查詢到。每次refresh的時候都會生成一個新的segment,太多的Segment會佔用過多的資源,並且每一個搜索請求都會遍歷全部的Segment,Segment過多會致使搜索變慢,因此ES會按期合併Segment,減小Segment的個數,並將Segment和併爲一個大的Segment;在操做Segment時,會維護一個Commit Point文件,其中記錄了全部Segment的信息;同時維護.del文件用於記錄全部刪除的Segment信息。
  單個倒排索引文件被稱爲Segment。多個Segment彙總在一塊兒,就是Lucene的索引,對應的就是ES中的shard。
  Lucene倒排索引由單詞詞典及倒排列表組成:
  單詞詞典:記錄全部文檔的單詞,記錄單詞到倒排列表的關係,數據量比較大,通常採用B+樹,哈希拉鍊法實現。
  倒排列表:記錄單詞對應的文檔集合,由倒排索引項組成。倒排索引項結構如表所示: 其中,文檔ID:記錄單詞所在文檔的ID;詞頻:記錄單詞在文檔中出現的次數;位置:記錄單詞在文檔中的位置;偏移:記錄單詞的開始位置,結束位置。

    

  5)每隔必定的時間(默認30分鐘),ES會調用Flush操做,Flush操做會調用Refresh將Index Buffer清空;而後調用fsync將緩存中的Segments寫入磁盤;隨後清空Transaction Log。同時當Transaction Log空間(默認512M)後也會觸發Flush操做。

9.副本分片索引文檔

  當主分片完成索引操做後,會循環處理要寫的全部副本分片,向副本分片所在的節點發送請求。副本分片執行和主分片同樣的文檔寫入流程,而後返回寫入結果給主分片節點。

10.請求返回

  主分片收到副本分片的響應後,會執行finish()操做,將收到的響應信息返回給Coordinate節點,告知Coordinate節點文檔寫入分片成功、失敗的狀況;coordinate節點收到響應後,將索引執行狀況返回給客戶端。當文檔寫入失敗時,主分片節點會向Master節點返送shardFieled請求,由於主副本分片未同步,Master會更新集羣的狀態,將寫失敗的副本分片從in-sync-allocation中去除;同時在路由表中將該分片的狀態改成unassigned,即未分配狀態。 

 

學習來源:

  阮一鳴《Elasticsearch核心技術與實戰》

  張超《Elasticsearch 源碼解析與優化實戰

相關文章
相關標籤/搜索