一、副本分片介紹
什么是副本分片? |
副本分片的主要目的就是為了故障轉移,如果持有主分片的節點掛掉了,一個副本分片就會晉升為主分片的角色。
在索引寫入時,副本分片做着與主分片相同的工作。新文檔首先被索引進主分片然后再同步到其它所有的副本分片。增加副本數並不會增加索引容量。
無論如何,副本分片可以服務於讀請求,如果你的索引也如常見的那樣是偏向查詢使用的,那你可以通過增加副本的數目來提升查詢性能,但也要為此,增加額外的硬件資源。
Elasticsearch內部分片處理機制 |
逆向索引
與傳統的數據庫不同,在Elasticsearch中,每個字段里面的每個單詞都是可以被搜索的。如teacher:“zls,bgx,lidao,oldboy,alex”我們在搜索關鍵字oldboy時,所有包含oldboy的文檔都會被匹配到Elasticsearch的這個特性也叫做全文搜索。
為了支持這個特性,Elasticsearch中會維護一個叫做“invertedindex”(也叫逆向索引)的表,表內包含了所有文檔中出現的所有單詞,同時記錄了這個單詞在哪個文檔中出現過。
例:
當前有4個文檔
txt1:“zls,bgx,lidao”
txt2:“zls,oldboy,alex”
txt3:“bgx,lidao,oldboy”
txt4:“oldboy,alex”
那么Elasticsearch會維護下面一個數據結構表:
Term | txt1 | txt2 | txt3 | txt4 |
---|---|---|---|---|
zls | Y | Y | ||
bgx | Y | Y | ||
lidao | Y | Y | ||
oldboy | Y | Y | Y | |
alex | Y | Y |
隨意搜索任意一個單詞,Elasticsearch只要遍歷一下這個表,就可以知道有些文檔被匹配到了。
逆向索引里面不止記錄了單詞與文檔的對應關系,它還維護了很多其他有用的數據。如:每個文檔一共包含了多少個單詞,單詞在不同文檔中的出現頻率,每個文檔的長度,所有文檔的總長度等等。這些數據用來給搜索結果進行打分,如搜索zls時,那么出現zls這個單詞次數最多的文檔會被優先返回,因為它匹配的次數最多,和我們的搜索條件關聯性最大,因此得分也最多。
逆向索引是不可更改的,一旦它被建立了,里面的數據就不會再進行更改。這樣做就帶來了以下幾個好處:
-
1.沒有必要給逆向索引加鎖,因為不允許被更改,只有讀操作,所以就不用考慮多線程導致互斥等問題。
-
2.索引一旦被加載到了緩存中,大部分訪問操作都是對內存的讀操作,省去了訪問磁盤帶來的io開銷。
-
3.因為逆向索引的不可變性,所有基於該索引而產生的緩存也不需要更改,因為沒有數據變更。
-
4.使用逆向索引可以壓縮數據,減少磁盤io及對內存的消耗。
Segment |
既然逆向索引是不可更改的,那么如何添加新的數據,刪除數據以及更新數據?為了解決這個問題,lucene將一個大的逆向索引拆分成了多個小的段segment。每個segment本質上就是一個逆向索引。在lucene中,同時還會維護一個文件commit point,用來記錄當前所有可用的segment,當我們在這個commit point上進行搜索時,就相當於在它下面的segment中進行搜索,每個segment返回自己的搜索結果,然后進行匯總返回給用戶。
引入了segment和commit point的概念之后,數據的更新流程如下圖:

-
1.新增的文檔首先會被存放在內存的緩存中
-
2.當文檔數足夠多或者到達一定時間點時,就會對緩存進行commit
-
a. 生成一個新的segment,並寫入磁盤
-
b. 生成一個新的commit point,記錄當前所有可用的segment
-
c. 等待所有數據都已寫入磁盤
-
-
3.打開新增的segment,這樣我們就可以對新增的文檔進行搜索了
-
4.清空緩存,准備接收新的文檔
二、Elasticsearch如何合理分配索引分片
為什么要考慮副本分片數量? |
大多數ElasticSearch用戶在創建索引時通用會考慮一個重要問題是:我需要創建多少個分片?
分片分配是個很重要的概念, 很多用戶對如何分片都有所疑惑, 當然是為了讓分配更合理. 在生產環境中, 隨着數據集的增長, 不合理的分配策略可能會給系統的擴展帶來嚴重的問題。
同時, 這方面的文檔介紹也非常少。很多用戶只想要明確的答案而不僅僅一個數字范圍, 甚至都不關心隨意的設置可能帶來的問題。
首先,我們需要了解ES中以下幾個名詞,是做什么的:
集群(cluster):由一個或多個節點組成, 並通過集群名稱與其他集群進行區分
節點(node):單個ElasticSearch實例. 通常一個節點運行在一個隔離的容器或虛擬機中
索引(index):在ES中, 索引是一組文檔的集合(就是我們所說的一個日志)
分片(shard):因為ES是個分布式的搜索引擎, 所以索引通常都會分解成不同部分, 而這些分布在不同節點的數據就是分片. ES自動管理和組織分片, 並在必要的時候對分片數據進行再平衡分配, 所以用戶基本上不用擔心分片的處理細節,一個分片默認最大文檔數量是20億.
副本(replica):ES默認為一個索引創建5個主分片, 並分別為其創建一個副本分片. 也就是說每個索引都由5個主分片成本, 而每個主分片都相應的有一個copy.
對於分布式搜索引擎來說, 分片及副本的分配將是高可用及快速搜索響應的設計核心.主分片與副本都能處理查詢請求, 它們的唯一區別在於只有主分片才能處理索引請求.
謹慎分片 |
副本對搜索性能非常重要, 同時用戶也可在任何時候添加或刪除副本。額外的副本能給你帶來更大的容量, 更高的呑吐能力及更強的故障恢復能力。
當在ElasticSearch集群中配置好你的索引后, 你要明白在集群運行中你無法調整分片設置。既便以后你發現需要調整分片數量, 你也只能新建創建並對數據進行重新索引(reindex)(雖然reindex會比較耗時, 但至少能保證你不會停機)。
主分片的配置與硬盤分區很類似, 在對一塊空的硬盤空間進行分區時, 會要求用戶先進行數據備份, 然后配置新的分區, 最后把數據寫到新的分區上。
在分片時,主要考慮數據集的增長趨勢,一定要做到不要過度分片,並不是分片越多越好,從ES社區用戶對這個熱門主題(分片配置)的分享數據來看, 用戶可能認為過度分配是個絕對安全的策略(這里講的過度分配是指對特定數據集, 為每個索引分配了超出當前數據量(文檔數)所需要的分片數)。
稍有富余是好的, 但過度分配分片卻是大錯特錯. 具體定義多少分片很難有定論, 取決於用戶的數據量和使用方式. 100個分片, 即便很少使用也可能是好的;而2個分片, 即便使用非常頻繁, 也可能是多余的.
我們要熟知以下幾點內容:
1.每分配一個分片,都會有額外的成本。
2.每個分片本質上就是一個Lucene索引,因此會消耗相應的文件句柄,內存和CPU資源。
3.每個搜索請求會調度到索引的每個分片中。如果分片分散在不同的節點倒是問題不太。但當分片開始競爭相同的硬件資源時,性能便會逐步下降。
4.ES使用詞頻統計來計算相關性。當然這些統計也會分配到各個分片上。如果在大量分片上只維護了很少的數據,則將導致最終的文檔相關性較差。
大規模數據集場景 |
如果真的擔心數據的快速增長, 我們建議你多關心這條限制: ElasticSearch推薦的最大JVM堆空間是30~32G, 所以把你的分片最大容量限制為30GB, 然后再對分片數量做合理估算. 例如, 你認為你的數據能達到200GB, 我們推薦你最多分配7到8個分片.
總之, 不要現在就為你可能在三年后才能達到的10TB數據做過多分配. 如果真到那一天, 你也會很早感知到性能變化的.
盡管本部分並未詳細討論副本分片, 但我們推薦你保持適度的副本數並隨時可做相應的增加. 如果你正在部署一個新的環境, 也許你可以參考我們的基於副本的集群的設計.這個集群有三個節點組成, 每個分片只分配了副本. 不過隨着需求變化, 你可以輕易的調整副本數量.
對大數據集, 我們非常鼓勵你為索引多分配些分片--當然也要在合理范圍內. 上面講到的每個分片最好不超過30GB的原則依然使用.
不過, 你最好還是能描述出每個節點上只放一個索引分片的必要性. 在開始階段, 一個好的方案是根據你的節點數量按照1.5~3倍的原則來創建分片. 例如:如果你有3個節點, 則推薦你創建的分片數最多不超過9(3x3)個.
隨着數據量的增加,如果你通過集群狀態API發現了問題,或者遭遇了性能退化,則只需要增加額外的節點即可. ES會自動幫你完成分片在不同節點上的分布平衡.
再強調一次, 雖然這里我們暫未涉及副本節點的介紹, 但上面的指導原則依然使用: 是否有必要在每個節點上只分配一個索引的分片. 另外, 如果給每個分片分配1個副本, 你所需的節點數將加倍. 如果需要為每個分片分配2個副本, 則需要3倍的節點數.
總結 |
再次聲明, 數據分片也是要有相應資源消耗,並且需要持續投入.
當索引擁有較多分片時, 為了組裝查詢結果, ES必須單獨查詢每個分片(當然並行的方式)並對結果進行合並. 所以高性能IO設備(SSDs)和多核處理器無疑對分片性能會有巨大幫助. 盡管如此, 你還是要多關心數據本身的大小,更新頻率以及未來的狀態. 在分片分配上並沒有絕對的答案, 只希望大家能從本博客中受益.
三、分片操作實戰
分片 |
正如上文中提到,創建分片,不超過3倍,在本課程中,我們有兩個節點,所以我們可以設置6個分片。
#在每個節點上執行,分配1個副本6個分片 [root@elkstack01 ~]# curl -XPUT 10.0.0.51:9200/_template/my_template -d' { "template": "*", "settings": { "index": { "number_of_shards": 6, "number_of_replicas": 1 } } }' #返回結果為true,分片成功 {"acknowledged":true}
測試提交數據 |
打開瀏覽器,訪問:http://10.0.0.51:9100/

驗證索引及頁面詳解 |

主節點和副本節點的區別 |
主節點的職責:
統計各node節點狀態信息、集群狀態信息統計、索引的創建和刪除、索引分配的管理、關閉node節點等。
副本節點的職責:
同步數據,等待機會成為Master(當主節點宕機或者重啟時)。
四、集群檢測實戰
檢測集群狀態 |
在linux中,我們可以通過curl命令獲取集群的狀態.
[root@elkstack02 ~]# curl –sXGET http://10.0.0.51:9200/_cluster/health?pretty=true
執行結果如下圖所示:
獲取到的是一個json格式的返回值,那就可以通過python對其中的信息進行分析,例如對status進行分析,如果等於green(綠色)就是運行在正常,等於yellow(黃色)表示副本分片丟失,red(紅色)表示主分片丟失。

python腳本檢測 |
#編寫python腳本 [root@elkstack01 ~]# vim es_cluster_status.py #!/usr/bin/env python #coding:utf-8 #Author:_DriverZeng_ #Date:2017.02.12 import smtplib from email.mime.text import MIMEText from email.utils import formataddr import subprocess body = "" false = "false" clusterip = "10.0.0.51" obj = subprocess.Popen(("curl -sXGET http://"+clusterip+":9200/_cluster/health?pretty=true"),shell=True, stdout=subprocess.PIPE) data = obj.stdout.read() data1 = eval(data) status = data1.get("status") if status == "green": print "\033[1;32m 集群運行正常 \033[0m" elif status == "yellow": print "\033[1;33m 副本分片丟失 \033[0m" else: print "\033[1;31m 主分片丟失 \033[0m" #執行結果如下 [root@elkstack01 ~]# python es_cluster_status.py 集群運行正常