1. 程式人生 > 程式設計 >ElasticSearch合理分配索引分片原理

ElasticSearch合理分配索引分片原理

Elasticsearch 是一個非常通用的平臺,支援各種使用者例項,併為組織資料和複製策略提供了極大的靈活性。但是,這種靈活性有時會使我們很難在早期確定如何很好地將資料組織成索引和分片,尤其是不熟悉 Elastic Stack。雖然不一定會在首次啟動時引起問題,但隨著資料量的增長,它們可能會導致效能問題。群集擁有的資料越多,糾正問題也越困難,因為有時可能需要重新索引大量資料。

因此,當我們遇到效能問題時,往往可以追溯到索引方式以及叢集中分片的數量。那麼就會遇到問題,我們應該有多少分片以及我的分片應該有多大。

一、什麼是分片?

假如我們的叢集的架構如下圖:

ElasticSearch合理分配索引分片原理

叢集(cluster): 由一個或多個節點組成,並通過叢集名稱與其他叢集進行區分

節點(node): 單個 ElasticSearch 例項. 通常一個節點執行在一個隔離的容器或虛擬機器中

索引(index): 在 ES 中,索引是一組文件的集合

分片(shard): 因為 ES 是個分散式的搜尋引擎,所以索引通常都會分解成不同部分,而這些分佈在不同節點的資料就是分片. ES自動管理和組織分片,並在必要的時候對分片資料進行再平衡分配,所以使用者基本上不用擔心分片的處理細節.

副本(replica): ES 預設為一個索引建立 5 個主分片,並分別為其建立一個副本分片. 也就是說每個索引都由 5 個主分片成本,而每個主分片都相應的有一個 copy。對於分散式搜尋引擎來說,分片及副本的分配將是高可用及快速搜尋響應的設計核心.主分片與副本都能處理查詢請求,它們的唯一區別在於只有主分片才能處理索引請求.副本對搜尋效能非常重要,同時使用者也可在任何時候新增或刪除副本。額外的副本能給帶來更大的容量,更高的呑吐能力及更強的故障恢復能力。

如上圖,有叢集兩個節點,並使用了預設的分片配置. ES自動把這5個主分片分配到2個節點上,而它們分別對應的副本則在完全不同的節點上。其中 node1 有某個索引的分片1、2、3和副本分片4、5,node2 有該索引的分片4、5和副本分片1、2、3。

當資料被寫入分片時,它會定期釋出到磁碟上的不可變的 Lucene 分段中用於查詢。隨著分段數量的增長,這些分段會定期合併為更大的分段。 此過程稱為合併。 由於所有分段都是不可變的,這意味著所使用的磁碟空間通常會在索引期間波動,因為需要在刪除替換分段之前建立新的合併分段。 合併可能非常耗費資源,特別是在磁碟I / O方面。

分片是 Elasticsearch 叢集分發資料的單元。 Elasticsearch 在重新平衡資料時可以移動分片的速度,例如發生故障後,將取決於分片的大小和數量以及網路和磁碟效能。

注1:避免使用非常大的分片,因為這會對群集從故障中恢復的能力產生負面影響。 對分片的大小沒有固定的限制,但是通常情況下很多場景限制在 50GB 的分片大小以內。

注2:當在ElasticSearch叢集中配置好你的索引後,你要明白在叢集執行中你無法調整分片設定. 既便以後你發現需要調整分片數量,你也只能新建建立並對資料進行重新索引(reindex)(雖然reindex會比較耗時,但至少能保證你不會停機).
主分片的配置與硬碟分割槽很類似,在對一塊空的硬碟空間進行分割槽時,會要求使用者先進行資料備份,然後配置新的分割槽,最後把資料寫到新的分割槽上。

注3:儘可能使用基於時間的索引來管理資料保留期。 根據保留期將資料分組到索引中。 基於時間的索引還可以輕鬆地隨時間改變主分片和副本的數量,因為可以更改下一個要生成的索引。

二、索引和分片是否是空閒的

對於每個 Elasticsearch 索引,有關對映和狀態的資訊都儲存在叢集狀態中。它儲存在記憶體中以便快速訪問。 因此,在群集中具有大量索引可能導致較大的群集狀態,尤其是在對映較大的情況下。 這可能會變得很慢,因為所有更新都需要通過單個執行緒完成,以便在更改叢集中分佈之前保證一致性。
每個分片都有需要儲存在記憶體中的資料並使用堆空間。 這包括在分片級別儲存資訊的資料結構,但也包括在分段級別的資料結構,以便定義資料駐留在磁碟上的位置。 這些資料結構的大小不固定,並且會根據使用場景不同而有所不同。然而,分段相關開銷的一個重要特徵是它與分段的大小不嚴格成比例。 這意味著與較小的分段相比,較大的分段每個資料量的開銷較小。 差異可能很大。為了能夠為每個節點儲存儘可能多的資料,管理堆的使用並儘可能減少開銷變得很重要。 節點擁有的堆空間越多,它可以處理的資料和分片就越多。
因此,索引和分片在叢集視角下不是空閒的,因為每個索引和分片都存在一定程度的資源開銷。

分配的每個分片都是有額外的成本的:

每個分片本質上就是一個Lucene索引,因此會消耗相應的檔案控制代碼,記憶體和CPU資源

每個搜尋請求會排程到索引的每個分片中. 如果分片分散在不同的節點倒是問題不太. 但當分片開始競爭相同的硬體資源時,效能便會逐步下降

ES 使用詞頻統計來計算相關性. 當然這些統計也會分配到各個分片上。如果在大量分片上只維護了很少的資料,則將導致最終的文件相關性較差。

注1:小的分片會造成小的分段,從而會增加開銷。我們的目的是將平均分片大小控制在幾 GB 到幾十 GB 之間。對於基於時間的資料的使用場景來說,通常將分片大小控制在 20GB 到 40GB 之間。

注2:由於每個分片的開銷取決於分段的數量和大小,因此通過 forcemerge 操作強制將較小的分段合併為較大的分段,這樣可以減少開銷並提高查詢效能。 理想情況下,一旦不再向索引寫入資料,就應該這樣做。 請注意,這是一項比較耗費效能和開銷的操作,因此應該在非高峰時段執行。

注3:我們可以在節點上保留的分片數量與可用的堆記憶體成正比,但 Elasticsearch 沒有強制的固定限制。 一個好的經驗法則是確保每個節點的分片數量低於每GB堆記憶體配置20到25個分片。 因此,具有30GB堆記憶體的節點應該具有最多600-750個分片,但是低於該限制可以使其保持更好。 這通常有助於叢集保持健康。

注4:如果擔心資料的快速增長,建議根據這條限制: ElasticSearch推薦的最大JVM堆空間 是 30~32G,所以把分片最大容量限制為 30GB,然後再對分片數量做合理估算。例如,如果的資料能達到 200GB,則最多分配7到8個分片。

注5:如果是基於日期的索引需求,並且對索引資料的搜尋場景非常少. 也許這些索引量將達到成百上千,但每個索引的資料量只有1GB甚至更小. 對於這種類似場景,建議是隻需要為索引分配1個分片。如果使用ES的預設配置(5個分片),並且使用 Logstash 按天生成索引,那麼 6 個月下來,擁有的分片數將達到 890 個. 再多的話,你的叢集將難以工作--除非提供了更多(例如15個或更多)的節點。想一下,大部分的 Logstash 使用者並不會頻繁的進行搜尋,甚至每分鐘都不會有一次查詢. 所以這種場景,推薦更為經濟使用的設定. 在這種場景下,搜尋效能並不是第一要素,所以並不需要很多副本。 維護單個副本用於資料冗餘已經足夠。不過資料被不斷載入到記憶體的比例相應也會變高。如果索引只需要一個分片,那麼使用 Logstash 的配置可以在 3 節點的叢集中維持執行 6 個月。當然你至少需要使用 4GB 的記憶體,不過建議使用 8GB,因為在多資料雲平臺中使用 8GB 記憶體會有明顯的網速以及更少的資源共享.

三、分片大小如何影響效能

在Elasticsearch中,每個查詢在每個分片的單個執行緒中執行。 但是,可以並行處理多個分片,對同一分片也可以進行多個查詢和聚合。

這意味著,如果不涉及快取,則最小查詢延遲將取決於資料、查詢型別以及分片的大小。 查詢大量小的分片將使每個分片的處理速度更快,但是需要按順序排隊和處理更多的任務,它不一定比查詢較少數量的較大分片更快。 如果存在多個併發查詢,則擁有大量小分片也會降低查詢吞吐量。
從查詢效能角度確定最大分片大小的最佳方法是使用實際資料和查詢進行基準測試。 始終以查詢和載入索引的節點在生產中需要處理的內容基準,因為優化單個查詢可能會產生誤導性結果。

四、如何管理分片大小

當使用基於時間的索引時,通常每個索引都與固定的時間段相關聯。 每天的索引非常常見,通常用於儲存保留期短的或每日量大的資料。 這些允許以合適的粒度管理保留期,並且可以輕鬆調整日常基礎量。 具有較長保留期的資料,特別是如果每日的量不能保證使用每天的索引,通常使用每週或每月的索引以保證分片大小。 這減少了隨著時間的推移需要儲存在叢集中的索引和分片的數量。

注:如果使用基於時間的索引,這個時間是某個固定的時間段,那麼需要根據資料的保留期限和預期的資料量來調整每個索引所覆蓋的時間段,以達到目標分片的大小。也就是說,如果我們要確定最終分片的大小,則需要根據我們的資料儲存的期限以及預估預期的資料量來調整我們索引需要按照天還是周還是月的時間來進行評估。
當資料量可以合理預測並且變化緩慢時,具有固定時間間隔的基於時間的索引很有效。 如果索引快速變化,則很難保持統一的目標分片大小。為了能夠更好地處理這種型別的場景,引入了 Rollover and Shrink API 這些為索引和分片的管理方式增加了很多靈活性,特別是對於基於時間的索引。

Rollover and Shrink API 可以指定應包含的文件和索引的數量和/或應該向其寫入最大期限的文件。 一旦超出其中一個標準,Elasticsearch 就可以觸發建立新索引,無需停機即可完成寫入。 可以切換到特定大小的新索引,而不是讓每個索引覆蓋特定的時間段,這使得可以更容易地為所有索引實現均勻的分片大小。如果需要更新資料,在使用此API時,事件的時間戳與其所處的索引之間不再存在明顯的連結,這可能會使更新效率大大降低,因為每次更新都需要在搜尋之前進行。

注:如果我們有基於時間的不可變資料,其中資料量可能會隨時間發生顯著變化,就可以考慮使用 Rollover API,通過動態更改每個索引所涵蓋的時間段來實現最佳目標分片大小。 這提供了極大的靈活性,並且可以幫助避免在資料量不可預測時具有太大或太小的分片。

Shrink API 允許我們將現有索引縮小為具有較少主分片的新索引。 如果在索引期間需要跨節點均勻擴充套件分片,但這會導致分片太小,一旦索引不再被索引,此 API 可用於減少主分片的數量。 這將生成更大的分片,更適合長期儲存資料。
如果需要讓每個索引覆蓋特定的時間段,並且希望能夠在大量節點上擴充套件索引,請考慮使用 Shrink API 在索引不再編入索引時減少主分片的數量。 如果最初配置了太多分片,此 API 還可用於減少分片數量。

五、總結

關於如何在索引和分片之間最佳地分佈資料,這將取決於所使用的場景的細節,有時很難確定如何最好地應用可用的建議。

資料分片也是要有相應資源消耗,並且需要持續投入。當索引擁有較多分片時,為了組裝查詢結果,ES 必須單獨查詢每個分片(當然並行的方式)並對結果進行合併。所以高效能 IO 裝置(SSDs)和多核處理器無疑對分片效能會有巨大幫助。儘管如此,還是要多關心資料本身的大小,更新頻率以及未來的狀態。在分片分配上並沒有絕對的答案。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。