ElasticSearch 集群
首先看下ElasticSearch(ES)的架構:
術語解釋:
- cluster:代表一個集群,集群中有多個節點,其中有一個master節點,master通過選舉自動產生;
- shards:代表索引分片,ES可以把一個完整的索引分成多個分片,並將它們分布到不同的節點上,從而構成分布式索引;
- replicas:代表索引副本,副本可以保證系統的高可用性,當某個節點的某個分片損壞時可以從副本中恢復,此外,多個分片副本還可以起到負載均衡的作用;
- recovery:代表數據恢復,ES在有節點加入或退出時會根據機器的負載對索引分片進行重新分配;
- river:代表ES的一個數據源,它是以插件方式存在的一個ES服務,通過讀取river中的數據並把它索引到ES中,官方的river有couchDB、RabbitMQ、Kafka、 Wikipedia等;
- geteway:代表ES索引快照的存儲方式,ES默認是把索引存放到內存中,當內存滿了再持久化到磁盤。geteway對索引快照進行存儲,當這個集群關閉再重新啟動時就會從geteway中讀取索引備份數據。ES支持多種類型的gateway,如本地文件系統(默認),分布式文件系統(HDFS);
-
discovery.zen,ES自動發現節點的機制,ES是一個基於P2P協議的系統,它先通過廣播尋找存在的節點,再通過多播協議來進行節點之間的通信,同時也支持點對點的交互;
- transport,代表ES內部節點之間或集群與客戶端的交互方式,默認使用TCP協議,同時支持HTTP協議(json格式)、thrift、servlet、zeroMQ、memcached等傳輸協議(通過插件方式集成);
ES的分布式操作大多是自動完成的:
1、跨節點平衡集群中各節點的索引與搜索負載;
2、自動復制索引數據以提供冗余副本,防止硬件錯誤導致數據丟失;
3、自動在節點之間路由,以幫助找到檢索的數據;
4、無縫擴展或者恢復集群;
node(節點)是ES運行中的實例,一個或多個具有相同cluster.name的節點構成一個cluster(集群),它們協同工作,共享數據,並共同分擔工作負載。
集群中的一個節點會被選為master,它將負責管理集群范疇的變更,例如創建或刪除索引,在集群中添加或刪除節點,但master無需參與文檔層面的變更和搜索,這意味着僅有一個master並不會因流量增長而成為瓶頸。
作為用戶,我們可以訪問包括master在內的集群中的任一節點,每個節點都知道各個文檔的位置,並能夠將我們的請求直接轉發到擁有我們想要的數據的節點,無論我們訪問的是哪個節點它都會控制從擁有數據的節點收集響應的過程,並返回給客戶端最終的結果,這一切都是由ES透明管理的。
1、添加索引
在ES中,分片用來分配集群中的數據。把分片想象成一個數據的容器。數據被存儲在分片中,然后分片又被分配在集群的節點上。當你的集群擴展或者縮小時,elasticsearch會自動的在節點之間遷移分配分片,以便集群保持均衡。
分片分為 主分片(primary shard) 以及 從分片(replica shard) 兩種:
- 主分片,在你的索引中,每一個文檔都屬於一個主分片。理論上主分片對存儲多少數據是沒有限制的,但分片的最大數量完全取決於你的實際狀況:硬件的配置、文檔的大小和復雜度、如何索引和查詢你的文檔,以及你期望的響應時間。
- 從分片,從分片只是主分片的一個副本,它用於提供數據的冗余副本,在硬件故障時提供數據保護,同時服務於搜索和檢索這種只讀請求。
索引中的主分片的數量在索引創建后就固定下來了,但是從分片的數量可以隨時改變。
接下來,我們在空的單節點集群中上創建一個叫做blogs的索引。一個索引默認設置了5個主分片,但是為了演示,我們這里只設置3個主分片和一組從分片(每個主分片有一個從分片對應):
PUT /blogs { "settings" : { "number_of_shards" : 3, "number_of_replicas" : 1 } }
現在,我們的集群看起來就像下圖所示了有索引的單節點集群,這三個主分片都被分配在Node 1。
在ES集群中可以監控統計很多信息,其中最重要的就是:集群健康(cluster health)。它的 status 有 green、yellow、red 三種;
GET /_cluster/health
返回:
{
"cluster_name": "elasticsearch",
"status": "yellow",
"timed_out": false,
"number_of_nodes": 1,
"number_of_data_nodes": 1,
"active_primary_shards": 3,
"active_shards": 3,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 3
}
其中status可以告訴我們當前集群是否處於一個可用的狀態。三種顏色分別代表:
狀態 | 意義 |
---|---|
green |
所有主分片和從分片都可用 |
yellow |
所有主分片可用,但存在不可用的從分片 |
red |
存在不可用的主要分片 |
集群的健康狀況yellow意味着所有的 主分片(primary shards) 啟動並且運行了,這時集群已經可以成功的處理任意請求,但是 從分片(replica shards) 沒有完全被激活。事實上,當前這3個從分片都處於unassigned(未分配)的狀態,它們還未被分配到節點上。在同一個節點上保存相同的數據副本是沒有必要的,如果這個節點故障了,就等同於所有的數據副本也丟失了。
2、容錯轉移
為了提高系統的可用性,生產環境幾乎不會使用單節點ES集群。
下面介紹如何使用雙節點集群(cluster-two-nodes),只要第二個節點與第一個節點的cluster.name相同(參見./config/elasticsearch.yml文件中的配置),它就能自動發現並加入到第一個節點的集群中。如果沒有,請結合日志找出問題所在。這可能是多播(multicast)被禁用,或者防火牆阻止了節點間的通信。
如下圖,雙節點集群——所有的主分片和從分片都被分配:
當第二個節點加入后,就產生了三個 從分片(replica shards) ,它們分別於三個主分片一一對應。也就意味着即使有一個節點發生了損壞,我們可以保證數據的完整性。
所有被索引的新文檔都會先被存儲在主分片中,之后才會被平行復制到關聯的從分片上。這樣可以確保我們的文檔在主節點和從節點上都能被檢索。
3、橫向擴展
隨着應用需求的增長,我們該如何擴展?如果我們啟動第三個節點,集群內會自動重組,這時便成為了三節點集群(cluster-three-nodes)。
分片已經被重新分配以平衡負載:
在Node 1和Node 2中分別會有一個分片被移動到Node 3上,這樣一來,每個節點上就都只有兩個分片了。這意味着每個節點的硬件資源(CPU、RAM、I/O)被更少的分片共享,所以每個分片就會有更好的性能表現。
分片本身就是一個非常成熟的搜索引擎,它可以使用單個節點的所有資源。我們一共有6個節點(3個主分片和3個從分片),因此最多可以擴展到6個節點,每個節點上有一個分片,這樣每個分片都可以使用到所在節點100%的資源了。
前面提到,主分片的數量在索引創建時就確定了,而從分片的數量可以隨時調整:
PUT /blogs/_settings { "number_of_replicas" : 2 }
將從分片的數量增加到2份:
從圖中可以看出,現在blogs的索引總共有9個分片:3個主分片和6個從分片。也就是說,現在我們就可以將總節點數擴展到9個,就又會變成一個節點一個分片的狀態了。最終我們得到了三倍搜索性能的三節點集群。
4、故障恢復
如果上面的三節點集群中有一個節點發生故障,例如:
被殺掉的節點是主節點。而為了集群的正常工作必須需要一個主節點,所以首先進行的進程就是從各節點中選擇了一個新的主節點:Node 2。
主分片1和2在我們殺掉Node 1后就丟失了,我們的索引在丟失主節點的時候是不能正常工作的。如果我們在這個時候檢查集群健康狀態,將會顯示red:存在不可用的主節點!
幸運的是,丟失的兩個主分片的完整拷貝在存在於其他的節點上,所以新的主節點所完成的第一件事情就是將這些在Node 2和Node 3上的從分片提升為主分片,然后集群的健康狀態就變回至yellow。這個提升的進程是瞬間完成了,就好像按了一下開關。
那么為什么集群健康狀態依然是是yellow而不是green呢?是因為現在我們有3個主分片,但是我們之前設定了1個主分片有2個從分片,但是現在卻只有1份從分片,所以狀態無法變為green,不過我們可以不用太擔心這里:當我們再次殺掉Node 2的時候,我們的程序依舊可以在沒有丟失任何數據的情況下運行,因為Node 3中依舊擁有每個分片的備份。
如果我們重啟Node 1,集群就能夠重新分配丟失的從分片,這樣結果就會與三節點兩從集群一致。如果Node 1依舊還有舊節點的內容,系統會嘗試重新利用他們,並只會復制在故障期間的變更數據。
5、分布式存儲
當需要新增一個文檔到索引中時,需要為這個文檔找到一個主分片進行存儲,它按照下面的公式選擇主分片:
shard = HASH(文檔ID) % 主分片數量
其中,文檔ID也可以被替換成其它能唯一表示一個文檔的字符串。另外,主分片數量在索引創建時就已經確定了,運行過程中不允許修改,因此,同一個文檔總是會被路由到同一個主分片上。
ES集群如果包含多個節點,每個節點都可以服務所有請求,節點可以根據上面的方法計算出當前請求的文檔在哪個分片,然后轉發請求到該節點上。
參考文檔:
http://www.learnes.net/distributed_cluster/