
創作人:劉曉國
當我們開始使用 Elasticsearch 時,我們必須了解其中的一些重要的概念。這些概念的了解對于以後我們使用 Elastic Stack 是非常重要的。在今天的這篇文章裡,我們先來介紹一下在 Elastic Stack 中最重要的一些概念。
首先,我們來看下一下如下的這個圖:
Cluster
Cluster 也就是叢集的意思。
Elasticsearch 叢集由一個或多個節點組成,可通過其叢集名稱進行辨別。通常這個 Cluster 的名字是可以在 Elasticsearch 裡的配置檔案中設定的。在預設的情況下,如我們的 Elasticsearch 已經開始運作,那麼它會自動生成一個叫做 “Elasticsearch” 的叢集。我們可以在 config/elasticsearch.yml 裡定制我們的叢集的名字:
一個 Elasticsearch 的叢集就像是下面的一個布局:
帶有 NginX 代理及 Balancer 的架構圖是這樣的:
我們可以通過:
GET _cluster/state
來擷取整個 cluster 的狀态。這個狀态隻能被 master node 所改變。上面的接口傳回的結果是:
{
"cluster_name": "elasticsearch",
"compressed_size_in_bytes": 1920,
"version": 10,
"state_uuid": "rPiUZXbURICvkPl8GxQXUA",
"master_node": "O4cNlHDuTyWdDhq7vhJE7g",
"blocks": {},
"nodes": {...},
"metadata": {...},
"routing_table": {...},
"routing_nodes": {...},
"snapshots": {...},
"restore": {...},
"snapshot_deletions": {...}
}
Node
單個 Elasticsearch 執行個體。
在大多數環境中,每個節點都在單獨的盒子或虛拟機上運作。一個叢集由一個或多個 node 組成。在測試的環境中,我可以把多個 node 運作在一個 server 上。在實際的部署中,大多數情況還是需要一個 server 上運作一個 node。
根據 node 的作用,可以分為如下的幾種:
- master-eligible:可以作為主 node。一旦成為主 node,它可以管理整個 cluster 的設定及變化:建立,更新,删除 index;添加或删除 node;為 node 配置設定 shard
- data:資料 node
- ingest: 資料接入(比如 pipepline)
- machine learning (Gold/Platinum License)
一般來說,一個 node 可以具有上面的一種或幾種功能。我們可以在指令行或者 Elasticsearch 的配置檔案(Elasticsearch.yml)來定義:
Node類型 | 配置參數 | 預設值 |
---|---|---|
master-eligible | node.master | true |
data | node.data | |
ingest | node.ingest | |
machine learning | node.ml | true (除了OSS釋出版) |
你也可以讓一個 node 做專有的功能及角色。如果上面 node 配置參數沒有任何配置,那麼我們可以認為這個 node 是作為一個 coordination node。在這種情況下,它可以接受外部的請求,并轉發到相應的節點來處理。針對 master node,有時我們需要設定 cluster.remote.connect: false。
在實際的使用中,我們可以把請求發送給 data 節點,而不能發送給 master 節點。
我們可以通過對 config/elasticsearch.yml 檔案中配置來定義一個 node 在叢集中的角色:
在有些情況中,我們可以通過設定 node.voting_only 為 true 進而使得一個 node 在 node.master 為真的情況下,隻作為參加 voting 的功能,而不當選為 master node。這種情況為了避免腦裂情況發生。它通常可以使用一個 CPU 性能較低的 node 來擔當。
在一個叢集中,我們可以使用如下的一個指令來擷取目前可以進行 vote 的所有 master-eligible 節點:
GET /_cluster/state?filter_path=metadata.cluster_coordination.last_committed_config
你可能獲得類似如下清單的結果:
{
"metadata" : {
"cluster_coordination" : {
"last_committed_config" : [
"Xe6KFUYCTA6AWRpbw84qaQ",
"OvD79L1lQme1hi06Ouiu7Q",
"e6KF9L1lQUYbw84CTAemQl"
]
}
}
}
在整個 Elastic 的架構中,Data Node 和 Cluster 的關系表述如下:
上面的定義适用于 Elastic Stack 7.9 釋出版以前。在 Elastic Stack 7.9 之後,有了新的改進。
請詳細閱讀文章 “Elasticsearch:Node roles 介紹 - 7.9 之後版本”: https://elasticstack.blog.csdn.net/article/details/110947372
Document
Elasticsearch 是面向文檔的,這意味着您索引或搜尋的最小資料單元是文檔。
文檔在 Elasticsearch 中有一些重要的屬性:
- 它是獨立的。文檔包含字段(名稱)及其值。
- 它可以是分層的。可以将其視為文檔中的文檔。字段的值可以很簡單,就像位置字段的值可以是字元串一樣。它還可以包含其他字段和值。例如,位置字段可能包含城市和街道位址。
- 結構靈活。您的文檔不依賴于預定義的架構。例如,并非所有事件都需要描述值,是以可以完全省略該字段。但它可能需要新的字段,例如位置的緯度和經度。
文檔通常是資料的 JSON 表示形式。JSON over HTTP 是與 Elasticsearch 進行通信的最廣泛使用的方式,它是我們在本書中使用的方法。
例如,您的聚會網站中的事件可以在以下文檔中表示:
{
"name": "Elasticsearch Denver",
"organizer": "Lee",
"location": "Denver, Colorado, USA"
}
很多人認為 Document 相比較于關系資料庫,它相應于其中每個 record。
Type
類型是文檔的邏輯容器,類似于表是行的容器。
您将具有不同結構(模式)的文檔放在不同類型中。 例如,你可以使用一種類型來定義聚合組,并在人們聚集時為事件定義另一種類型。
每種類型的字段定義稱為映射。 例如,name 将映射為字元串,但 location 下的 geolocation 字段将映射為特殊的 geo_point 類型。 (我們探讨如何使用附錄A中的地理空間資料。)每種字段的處理方式都不同。 例如,你在名稱字段中搜尋單詞,然後按位置搜尋組以查找位于您居住地附近的組。
很多人認為 Elasticsearch 是 schema-less 的。大家都甚至認為 Elasticsearch 中的資料庫是不需要 mapping 的。其實這是一個錯誤的概念。schema-less 在 Elasticsearch 中正确的了解是,我們不需要事先定義一個類型關系資料庫中的 table 才使用資料庫。
在 Elasticsearch 中,我們開始可以不定義一個 mapping,而直接寫入到我們指定的 index 中。這個 index 的 mapping 是動态生成的 (當然我們也可以禁止這種行為)。其中的資料項的每一個資料類型是動态識别的。比如時間,字元串等,雖然有些資料類型,還是需要我們手動調整,比如 geo_point 等地理位置資料。
另外,它還有一個含義,同一個 type,我們在以後的資料輸入中,可能增加新的資料項,進而生産新的 mapping。這個也是動态調整的。
Elasticsearch 具有 schema-less 的能力,這意味着無需顯式指定如何處理文檔中可能出現的每個不同字段,即可對文檔建立索引。 啟用動态映射後,Elasticsearch 自動檢測并向索引添加新字段。 這種預設行為使索引和浏覽資料變得容易-隻需開始建立索引文檔,Elasticsearch 就會檢測布爾值,浮點數和整數值,日期和字元串,并将其映射到适當的 Elasticsearch 資料類型。
由于一些原因,在 Elasticsearch 6.0 以後,一個 Index 隻能含有一個 type。這其中的原因是:相同 index 的不同映射 type 中具有相同名稱的字段是相同; 在 Elasticsearch 索引中,不同映射 type 中具有相同名稱的字段在 Lucene 中被同一個字段支援。在預設的情況下是 _doc。在未來8.0的版本中,type 将被徹底删除。
Index
在 Elasticsearch 中,索引是文檔的集合。
每個 Index 一個或許多的 documents 組成,并且這些 document 可以分布于不同的 shard 之中。
很多人認為 index 類似于關系資料庫中的 database。這中說法是有些道理,但是并不完全相同。其中很重要的一個原因是,在Elasticsearch 中的文檔可以有 object 及 nested 結構。一個 index 是一個邏輯命名空間,它映射到一個或多個主分片,并且可以具有零個或多個副本分片。
每當一個文檔進來後,根據文檔的 id 會自動進行 hash 計算,并存放于計算出來的 shard 執行個體中,這樣的結果可以使得所有的 shard 都比較有均衡的存儲,而不至于有的 shard 很忙。
shard_num = hash(_routing) % num_primary_shards
在預設的情況下,上面的 _routing 既是文檔的 _id。如果有 routing 的參與,那麼這些文檔可能隻存放于一個特定的 shard,這樣的好處是對于一些情況,我們可以很快地綜合我們所需要的結果而不需要跨 node 去得到請求。比如針對 join 的資料類型。
從上面的公式我們也可以看出來,我們的 shard 數目是不可以動态修改的,否則之後也找不到相應的 shard 号碼了。必須指出的是,replica 的數目是可以動态修改的。
Shard
由于 Elasticsearch 是一個分布式搜尋引擎,是以索引通常會拆分為分布在多個節點上的稱為分片的元素。 Elasticsearch 自動管理這些分片的排列。 它還根據需要重新平衡分片,是以使用者無需擔心細節。
一個索引可以存儲超出單個結點硬體限制的大量資料。比如,一個具有 10 億文檔的索引占據1TB 的磁盤空間,而任一節點都沒有這樣大的磁盤空間;或者單個節點處理搜尋請求,響應太慢。
為了解決這個問題,Elasticsearch 提供了将索引劃分成多份的能力,這些份就叫做分片(shard)。當你建立一個索引的時候,你可以指定你想要的分片 (shard) 的數量。每個分片本身也是一個功能完善并且獨立的“索引”,這個“索引”可以被放置到叢集中的任何節點上。
分片之是以重要,主要有兩方面的原因:
- 允許你水準分割/擴充你的内容容量
- 允許你在分片(潛在地,位于多個節點上)之上進行分布式的、并行的操作,進而提高性能/吞吐量
有兩種類型的分片:Primary shard 和 Replica shard。
- Primary shard: 每個文檔都存儲在一個Primary shard。 索引文檔時,它首先在 Primary shard上編制索引,然後在此分片的所有副本上(replica)編制索引。索引可以包含一個或多個主分片。 此數字确定索引相對于索引資料大小的可伸縮性。 建立索引後,無法更改索引中的主分片數。
- Replica shard: 每個主分片可以具有零個或多個副本。 副本是主分片的副本,有兩個目的:
- 增加故障轉移:如果主要故障,可以将副本分片提升為主分片
- 提高性能:get 和 search 請求可以由主 shard 或副本 shard 處理。
預設情況下,每個主分片都有一個副本,但可以在現有索引上動态更改副本數。 永遠不會在與其主分片相同的節點上啟動副本分片。
下面的圖表示的是一個 index 有5個 shard 及1個 replica
這些 Shard 分布于不同的實體機器上:
我們可以為每個 Index 設定相應的 Shard 數值:
curl -XPUT http://localhost:9200/another_user?pretty -H 'Content-Type: application/json' -d '
{
"settings" : {
"index.number_of_shards" : 2,
"index.number_of_replicas" : 1
}
}
比如在上面的 REST 接口中,我們為 another_user 這個 index 設定了2個 shards,并且有一個 replica。一旦設定好 primary shard 的數量,我們就不可以修改了。這是因為 Elasticsearch 會依據每個 document 的 id 及 primary shard 的數量來把相應的 document 配置設定到相應的 shard 中。如果這個數量以後修改的話,那麼每次搜尋的時候,可能會找不到相應的 shard。
我們可以通過如下的接口來檢視我們的 index 中的設定:
curl -XGET http://localhost:9200/twitter/_settings?pretty
上面我們可以得到 twitter index 的設定資訊:
{
"twitter" : {
"settings" : {
"index" : {
"creation_date" : "1565618906830",
"number_of_shards" : "1",
"number_of_replicas" : "1",
"uuid" : "rwgT8ppWR3aiXKsMHaSx-w",
"version" : {
"created" : "7030099"
},
"provided_name" : "twitter"
}
}
}
}
Replica
預設情況下,Elasticsearch 為每個索引建立一個主分片和一個副本。這意味着每個索引将包含一個主分片,每個分片将具有一個副本。
配置設定多個分片和副本是分布式搜尋功能設計的本質,提供高可用性和快速通路索引中的文檔。主副本和副本分片之間的主要差別在于,隻有主分片可以接受索引請求。副本和主分片都可以提供查詢請求。
在上圖中,我們有一個 Elasticsearch 叢集,由預設分片配置中的兩個節點組成。 Elasticsearch 自動排列分割在兩個節點上的一個主分片。有一個副本分片對應于每個主分片,但這些副本分片的排列與主分片的排列完全不同。
請允許我們澄清一下:請記住,number_of_shards 值與索引有關,而不是與整個群集有關。此值指定每個索引的分片數(不是群集中的主分片總數)。
我們可以通過如下的接口來獲得一個 index 的健康情況:
http://localhost:9200/_cat/indices/twitter
上面的接口可以傳回如下的資訊:
更進一步的查詢,我們可以看出:
如果一個 index 顯示的是紅色,表面這個 index 至少有一個 primary shard 沒有被正确配置設定,并且有的 shard 及其相應的 replica 已經不能正常通路。 如果是綠色,表明 index 的每一個 shard 都有備份 (replica),并且其備份也成功複制在相應的 replica shard 之中。如果其中的一個 node 壞了,相應的另外一個 node 的 replica 将起作用,進而不會造成資料的丢失。
shard 健康
- 紅色:叢集中未配置設定至少一個主分片
- 黃色:已配置設定所有主副本,但未配置設定至少一個副本
- 綠色:配置設定所有分片
創作人簡介:
劉曉國,現為 Elastic 社群資深布道師。新加坡國立大學碩士,西北工業大學本碩。
曾就職于新加坡科技,康柏電腦,通用汽車,愛立信,諾基亞,Linaro 非營利組織(
Linux for ARM),Ubuntu,LinkMotion,Vantiq 等企業。從事過通信,電腦設計,計
算機作業系統,物聯網,汽車電子,雲實時事件處理,大資料搜尋等行業。從愛立信開
始,到後來的諾基亞,Ubuntu 從事社群工作有超過 15 年以上經曆。喜歡分享自己所學
到的知識,希望和大家一起分享及學習。
部落格:
https://elasticstack.blog.csdn.net/