ES GET/MGET 設計理解

ES的讀取分爲GET和Search兩種操作,這兩種讀取操作有較大的差異,本章我們主要分析下GET/MGET讀取操作。

GET/MGET必須指定三元組:_index、_type、_id(http://127.0.0.1:9200/_index/_type/_id),也就是說,根據文檔id從正排索引中獲取內容。

注:ElasticSearch中同時保存了正排索引和倒排索引,對該知識不清楚的可以參考:

深入理解正排索引與倒排索引(設計思想和數據結構)

GET基本流程

搜索和讀取文檔都屬於讀操作,可以從主分片或副分片中讀取數據。

讀取單個文檔的流程(圖片來自官網)可如下圖:

注:其中P->primary shard(主分片),R->replication shard (副分片)

步驟如下:

(1)客戶端向NODE1發送讀請求(此時NODE1作爲協調節點

(2)NODE1是同文檔ID來確定文檔屬於分片0,通過集羣狀態中的內容路由表信息獲取分片0有三個副本數據,位於三個節點中,此時它可以通過將請求發送到任意節點,圖上所示是將請求發送到NODE2。

(3)NODE2將文檔返回給NODE1,NODE1將文檔返回給客戶端(因爲只是獲取單個數據信息,不會涉及協調節點的聚合等操作)

注:NODE1在此流程中作爲協調節點,將客戶端請求輪詢發送到集羣的所有副本來實現負載均衡

瞭解ElasticSearch中節點角色也是很重要的,對節點角色不清楚的,可以參考:

ES(Elasticsearch)集羣節點角色

 

🤔思考:如果副分片還沒來得及同步主分片的最新數據或者其他原因導致還未同步怎麼辦?

在讀取時,如果文檔可能以及存在於主分片,但是還沒有複製到副分片。在這種情況下,讀請求命重副分片時可能會報告文檔不存在,但是命中主分片可能成功返回文檔,一旦寫請求成功返回給客戶端,則意味着文檔正在主分片和副分片都是可用的。

下面我們展示下GET詳細的流程圖:

以上我們展示了單個GET獲取數據的流程,那麼MGET又是什麼?

MGET

MGET批量查詢,通過封裝了單個GET請求實現,處理流程如下:

(1)遍歷請求,計算每個doc的路由信息,得到由shardId爲key組成的request map。這個過程並沒有在TransportSingleShardAction中實現,避免shardId會重複,這也是合併爲基於分片的請求過程。

(2)循環處理組織好的每個shard級請求,調用處理GET請求時使用TransportSingleShardAction#AsyncSingleAction處理單個doc(也就是異步調用GET邏輯處理業務)

(3)收集Response,全部Response返回後執行finishHim,可客戶端返回結果。

🤔思考:如果MGET一部分成功,一部分失敗怎麼辦?

同一個批量操作中各項操作時相互獨立的(每個操作都會返回一個請求回覆,而不是整個批量操作返回一個單獨的回覆),因此如果部分文檔讀取失敗,則不影響其他結果,檢索失敗的doc會在回覆信息中標出

設計性能的時候,批量的大小很關鍵,如果批量數據過大,那麼他們就會佔用過多的內存。如果批量太小,多次請求,網絡開銷就會變大,最佳的平衡點,取決於文檔的大小->如果文檔很大,每個批量處理中就少放幾篇,如果文檔很小,就多放幾篇,根據實際項目來判定

下圖爲示意圖:

 

MGET還是很重要的,一般來說,進行查詢的時候,如果一次性查詢多條數據的話,那麼一定要用batch批量操作的api(MGET),儘可能減少網絡開銷次數,可能可以將性能提升數倍,甚至十倍,非常重要。

GET API默認是實時的,實時的意思是寫完了可以立即讀取,但僅限於GET,MGET操作,不包括搜索(search)操作。在5.x版本之前,GET/MGET的實時讀取依賴於從translog中讀取實現,5.x版本之後改爲了refresh,因此係統對實時讀取的支持會對寫入速度有負面影響

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