Elasticsearch中一些重要概念
Cluster
Cluster 也就是集群的意思。Elasticsearch 集群由一个或多个节点组成,可通过其集群名称进行标识。通常这个 Cluster 的名字是可以在 Elasticsearch 里的配置文件中设置的。
在默认的情况下,如我们的 Elasticsearch 已经开始运行,那么它会自动生成一个叫做“elasticsearch”的集群。我们可以在 config/elasticsearch.yml 里定制我们的集群的名字:
#设置集群名字
cluster.name: es-itcast-cluster
一个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 做专有的功能及角色。如果上面 node 配置参数没有任何配置,那么我们可以认为这个 node 是作为一个 Coordinating node。在这种情况下,它可以接受外部的请求,并转发到相应的节点来处理。
在实际的使用中,我们可以把请求发送给 data 节点,而不能发送给 master 节点。我们可以通过对 elasticsearch.yml 文件中配置来定义一个 node 在集群中的角色:
在有些情况中,我们可以通过设置 node.voting_only 为 true 从而使得一个 node 在 node.master 为真的情况下,只作为参加 voting 的功能,而不当选为 master node。这种情况为了避免脑裂情况发生,它通常可以使用一个 CPU 性能较低的 node 来担当。
在整个 Elastic 的架构中,Data Node 和 Cluster 的关系表述如下:
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 类型。每种字段的处理方式都不同。例如,您在名称字段中搜索单词,然后按位置搜索组以查找位于您居住地附近的组。
很多人认为 Elasticsearch 是 schemaless 的,大家都甚至认为 Elasticsearch 中的数据库是不需要 mapping 的,其实这是一个错误的概念。schemaless 在 Elasticsearch 中正确的理解是,我们不需要事先定义一个类型关系数据库中的 table 才使用数据库。
在 Elasticsearch中,我们可以不开始定义一个 mapping,而直接写入到我们指定的 index 中。这个 index 的 mapping 是动态生成的。其中的数据项的每一个数据类型是动态识别的。比如时间,字符串等,虽然有些的数据类型还是需要我们手动调整,比如 geo_point 等地理位置数据。另外,它还有一个含义,同一个 type,我们在以后的数据输入中,可能增加新的数据项,从而生产新的 mapping,这个也是动态调整的。
由于一些原因,在 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 去得到请求
从上面的公式我们也可以看出来,我们的 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。
我们可以为每个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。一旦设置好 shard 的数量,我们就不可以修改了。这是因为 Elasticsearch 会依据每个 document 的 id 及 shard 的数量来把相应的 document 分配到相应的 shard 中。如果这个数量以后修改的话,那么每次搜索的时候,可能会找不到相应的 shard。
我们可以通过如下的接口来查看我们的 index 中的设置:
curl -XGET http://localhost:9200/users/_settings?pretty
上面我们可以得到 twitter index 的设置信息:
{ "users" : { "settings" : { "index" : { "creation_date" : "1587977298859", "number_of_shards" : "1", "number_of_replicas" : "1", "uuid" : "nK8W_WLsTnKYsyruxziwPQ", "version" : { "created" : "7050199" }, "provided_name" : "users" } } } }
replica
默认情况下,Elasticsearch 为每个索引创建一个主分片和一个副本。这意味着每个索引将包含一个主分片,每个分片将具有一个副本。
分配多个分片和副本是分布式搜索功能设计的本质,提供高可用性和快速访问索引中的文档。主副本和副本分片之间的主要区别在于只有主分片可以接受索引请求。副本和主分片都可以提供查询请求。
在上图中,我们有一个 Elasticsearch 集群,由默认分片配置中的两个节点组成。Elasticsearch 自动排列分割在两个节点上的五个主分片。有一个副本分片对应于每个主分片,但这些副本分片的排列与主分片的排列完全不同。再次,思考分配。
请允许我们澄清一下:请记住,number_of_shards 值与索引有关,而不是与整个群集有关。此值指定每个索引的分片数(不是群集中的主分片总数)。
我们可以通过如下的接口来获得一个 index 的健康情况:
http://localhost:9200/_cat/indices/twitter
上面的接口可以返回如下的信息:
更进一步的查询,我们可以看出:
如果一个
index 显示的是红色,表面这个 index 至少有1个 primary shard 没有被正确分配,并且有的 shard 及其相应的
replica 已经不能正常访问。如果是绿色,表明 index 的每一个 shard 都有备份,并且其备份也成功复制在相应的 replica
shard 之中。如果其中的一个 node 坏了,相应的另外一个 node 的 replica 或其 primary shard
将起作用,从而不会造成数据的丢失。
shard 健康
-
红色:集群中未分配至少一个主分片;
-
黄色:已分配所有主副本,但至少一个副本分片未 被分配;
-
绿色:已分配所有分片。