【Elasticsearch学习】之一图读懂文档索引全过程
ES索引過程詳解:
1.客戶端發送索引請求。
客戶端向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輪詢算法,進行發送節點的選取。
2.參數檢查。
對請求中的參數進行檢查,檢查參數是否合法,不合法的參數直接返回失敗給客戶端。
3.數據預處理
如果請求指定了pipeline參數,則對數據進行預處理,數據預處理的節點為Ingest Node,如果接受請求的節點不具有數據處理能力,則轉發給其他能處理的節點。
在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 源碼解析與優化實戰》
總結
以上是生活随笔為你收集整理的【Elasticsearch学习】之一图读懂文档索引全过程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 打骂同居的女友算家暴吗
- 下一篇: SAP BSP应用有状态和无状态行为差异