天天看點

ElasticSearch的基本概念和叢集分布式底層實作

雲栖号資訊:【 點選檢視更多行業資訊

在這裡您可以找到不同行業的第一手的上雲資訊,還在等什麼,快來!

深度分頁引發的機器性能問題

最近碰到一個ElasticSearch深度分頁搜尋,導緻cpu占用過高問題,通過查閱ElasticSearch: 權威指南,了解到了深度分頁為何會引起機器資源占用:

在叢集系統中深度分頁

為了了解為什麼深度分頁是有問題的,讓我們假設在一個有5個主分片的索引中搜尋。當我們請求結果的第一頁(結果1到10)時,每個分片産生自己最頂端10個結果然後傳回它們給請求節(requesting node),它再排序這所有的50個結果以選出頂端的10個結果。

現在假設我們請求第1000頁——結果10001到10010。工作方式都相同,不同的是每個分片都必須産生頂端的10010個結果。然後請求節點排序這50050個結果并丢棄50040個!

你可以看到在分布式系統中,排序結果的資源和時間花費随着分頁的深入而成倍增長。這也是為什麼網絡搜尋引擎中任何語句不能傳回多于1000個結果的原因。

了解以上那段文字,有必要了解ElasticSearch叢集以及在叢集中是查詢的底層原理,本文試圖通過總結ElasticSearch基本概念和底層原理,加深自身了解,同時希望對使用者有所幫助,避免不必要的踩坑。

基本概念

索引(index)

“索引” 這個詞在 ElasticSearch 語境中包含多重意思:

索引(名詞):

類比傳統的關系型資料庫領域來說,索引相當于SQL中的一個資料庫。索引由其名稱(必須為全小寫字元)進行辨別,并通過引用此名稱完成文檔的建立、搜尋、更新及删除操作。

索引(動詞):

索引一個文檔就是存儲一個文檔到一個索引(名詞)中以便它可以被檢索和查詢到。這非常類似于SQL語句中的 INSERT關鍵詞,除了文檔已存在時新文檔會替換舊文檔情況之外。

反向索引:

關系型資料庫通過增加一個“索引”比如一個B樹(B-tree)索引到指定的列上,以便提升資料檢索速度。ElasticSearch 和 Lucene 使用了一個叫做 “反向索引” 的結構來達到相同的目的。

舉個例子,文檔和詞條之間的關系如下圖:

ElasticSearch的基本概念和叢集分布式底層實作

類型(Type)

類型是索引内部的邏輯分區(category/partition),然而其意義完全取決于使用者需求。是以,一個索引内部可定義一個或多個類型(type)。一般來說,類型就是為那些擁有相同的域的文檔做的預定義。類比傳統的關系型資料庫領域來說,類型相當于“表”。

文檔(Document)

文檔類似于一行完整的資料,在ElasticSearch裡面文檔是基于JSON格式進行表示的,文檔是索引和搜尋的原子機關,它是包含了一個或多個域(Field)的容器。每個文檔可以存儲不同的域集,但同一類型(Type)下的文檔至少應該有某種程度上的相似之處。

節點(Node)

一個運作中的 ElasticSearch執行個體稱為一個節點,而叢集是由一個或者多個擁有相同cluster.name配置的節點組成, 它們共同承擔資料和負載的壓力。

ES叢集中的節點有三種不同的類型:

主節點:負責管理叢集範圍内的所有變更,例如增加、删除索引,或者增加、删除節點等。主節點并不需要涉及到文檔級别的變更和搜尋等操作。可以通過屬性node.master進行設定。

資料節點:存儲資料和其對應的反向索引。預設每一個節點都是資料節點(包括主節點),可以通過node.data屬性進行設定。

協調節點:如果node.master和node.data屬性均為false,則此節點稱為協調節點,用來響應客戶請求,均衡每個節點的負載。

分片(Shard)

一個索引中的資料儲存在多個分片中,相當于水準分表。一個分片便是一個Lucene 的執行個體,它本身就是一個完整的搜尋引擎。我們的文檔被存儲和索引到分片内,但是應用程式是直接與索引而不是與分片進行互動。

一個分片可以是主分片或者副本分片。索引内任意一個文檔都歸屬于一個主分片,是以主分片的數目決定着索引能夠儲存的最大資料量。一個副本分片隻是一個主分片的拷貝。副本分片作為硬體故障時保護資料不丢失的備援備份,并為搜尋和傳回文檔等讀操作提供服務。

叢集分布式底層實作

以上我們對ElasticSearch的基本概念有了一個初步認識,接下來我們深入這些内部細節來幫助你更好的了解資料是如何在分布式系統中存儲和查詢的。

ES實際上就是利用分片來實作分布式。分片是資料的容器,文檔儲存在分片内,分片又被配置設定到叢集内的各個節點裡。當你的叢集規模擴大或者縮小時, ES會自動的在各節點中遷移分片,使得資料仍然均勻分布在叢集裡。

在索引建立的時候就已經确定了主分片數,但是副本分片數可以随時修改。預設情況下,一個索引會有5個主分片,而其副本可以有任意數量。

主分片和副本分片的狀态決定了叢集的健康狀态。每一個節點上都隻會儲存主分片或者其對應的一個副本分片,相同的副本分片不會存在于同一個節點中。如果叢集中隻有一個節點,則副本分片将不會被配置設定,此時叢集健康狀态為yellow,存在丢失資料的風險。

分布式文檔CRUD

索引新文檔(Create)

當使用者向一個節點送出了一個索引新文檔的請求,節點會計算新文檔應該加入到哪個分片(shard)中。每個節點都存儲有每個分片存儲在哪個節點的資訊,是以協調節點會将請求發送給對應的節點。注意這個請求會發送給主分片,等主分片完成索引,會并行将請求發送到其所有副本分片,保證每個分片都持有最新資料。

每次寫入新文檔時,都會先寫入記憶體中,并将這一操作寫入一個translog檔案(transaction log)中,此時如果執行搜尋操作,這個新文檔還不能被索引到。

ElasticSearch的基本概念和叢集分布式底層實作

ES會每隔1秒時間(這個時間可以修改)進行一次重新整理操作(refresh),此時在這1秒時間内寫入記憶體的新文檔都會被寫入一個檔案系統緩存(filesystem cache)中,并構成一個分段(segment)。此時這個segment裡的文檔可以被搜尋到,但是尚未寫入硬碟,即如果此時發生斷電,則這些文檔可能會丢失。

ElasticSearch的基本概念和叢集分布式底層實作

不斷有新的文檔寫入,則這一過程将不斷重複執行。每隔一秒将生成一個新的segment,而translog檔案将越來越大。

ElasticSearch的基本概念和叢集分布式底層實作

每隔30分鐘或者translog檔案變得很大,則執行一次fsync操作。此時所有在檔案系統緩存中的segment将被寫入磁盤,而translog将被删除(此後會生成新的translog)。

ElasticSearch的基本概念和叢集分布式底層實作

由上面的流程可以看出,在兩次fsync操作之間,存儲在記憶體和檔案系統緩存中的文檔是不安全的,一旦出現斷電這些文檔就會丢失。是以ES引入了translog來記錄兩次fsync之間所有的操作,這樣機器從故障中恢複或者重新啟動,ES便可以根據translog進行還原。

當然,translog本身也是檔案,存在于記憶體當中,如果發生斷電一樣會丢失。是以,ES會在每隔5秒時間或是一次寫入請求完成後将translog寫入磁盤。可以認為一個對文檔的操作一旦寫入磁盤便是安全的可以複原的,是以隻有在目前操作記錄被寫入磁盤,ES才會将操作成功的結果傳回發送此操作請求的用戶端。

此外,由于每一秒就會生成一個新的segment,很快将會有大量的segment。對于一個分片進行查詢請求,将會輪流查詢分片中的所有segment,這将降低搜尋的效率。是以ES會自動啟動合并segment的工作,将一部分相似大小的segment合并成一個新的大segment。合并的過程實際上是建立了一個新的segment,當新segment被寫入磁盤,所有被合并的舊segment被清除。

ElasticSearch的基本概念和叢集分布式底層實作

更新(Update)和删除(Delete)文檔

ES的索引是不能修改的,是以更新和删除操作并不是直接在原索引上直接執行。

每一個磁盤上的segment都會維護一個del檔案,用來記錄被删除的檔案。每當使用者提出一個删除請求,文檔并沒有被真正删除,索引也沒有發生改變,而是在del檔案中标記該文檔已被删除。是以,被删除的文檔依然可以被檢索到,隻是在傳回檢索結果時被過濾掉了。每次在啟動segment合并工作時,那些被标記為删除的文檔才會被真正删除。

更新文檔會首先查找原文檔,得到該文檔的版本号。然後将修改後的文檔寫入記憶體,此過程與寫入一個新文檔相同。同時,舊版本文檔被标記為删除,同理,該文檔可以被搜尋到,隻是最終被過濾掉。

讀操作(Read):查詢過程

查詢的過程大體上分為查詢(query)和取回(fetch)兩個階段。這個節點的任務是廣播查詢請求到所有相關分片,并将它們的響應整合成全局排序後的結果集合,這個結果集合會傳回給用戶端。

查詢階段

當一個節點接收到一個搜尋請求,則這個節點就變成了協調節點。

查詢過程分布式搜尋

ElasticSearch的基本概念和叢集分布式底層實作

第一步是廣播請求到索引中每一個節點的分片拷貝。查詢請求可以被某個主分片或某個副本分片處理,協調節點将在之後的請求中輪詢所有的分片拷貝來分攤負載。

每個分片将會在本地建構一個優先級隊列。如果用戶端要求傳回結果排序中從第from名開始的數量為size的結果集,則每個節點都需要生成一個from+size大小的結果集,是以優先級隊列的大小也是from+size。分片僅會傳回一個輕量級的結果給協調節點,包含結果集中的每一個文檔的ID和進行排序所需要的資訊。

協調節點會将所有分片的結果彙總,并進行全局排序,得到最終的查詢排序結果。此時查詢階段結束。

取回階段

查詢過程得到的是一個排序結果,标記出哪些文檔是符合搜尋要求的,此時仍然需要擷取這些文檔傳回用戶端。

協調節點會确定實際需要傳回的文檔,并向含有該文檔的分片發送get請求;分片擷取文檔傳回給協調節點;協調節點将結果傳回給用戶端

ElasticSearch的基本概念和叢集分布式底層實作

【雲栖号線上課堂】每天都有産品技術專家分享!

課程位址:

https://yqh.aliyun.com/zhibo

立即加入社群,與專家面對面,及時了解課程最新動态!

【雲栖号線上課堂 社群】

https://c.tb.cn/F3.Z8gvnK

原文釋出時間:2020-06-24

本文作者:張勇

本文來自:“

網際網路架構師 微信公衆号

”,了解相關資訊可以關注“[網際網路架構師](

https://mp.weixin.qq.com/s/3RVjWueqLkLCSKzn73815g