1.基本概念
1.1 节点(node)
一个ES的实例,本质上是一个java进程,生产环境一般建议一台机器上运行一个ES实例。
节点有如下分类:
(1)master节点:集群中的一个节点会被选为master节点,它将负责管理集群范畴的变更,例如创建或删除索引,添加节点到集群或从集群删除节点。master节点无需参与文档层面的变更和搜索,这意味着仅有一个master节点并不会因流量增长而成为瓶颈。任意一个节点都可以成为 master 节点。
(2)data节点:持有数据和倒排索引。默认情况下,每个节点都可以通过设定配置文件中的node.data属性为true(默认)成为数据节点。如果需要一个专门的主节点,应将其node.data属性设置为false。
(3)client节点:如果将node.master属性和node.data属性都设置为false,那么该节点就是一个客户端节点,扮演一个负载均衡的角色,将到来的请求路由到集群中的各个节点。
1.2 分片(shard)
ES提供了分片的机制,分片是一种存储容器,用来存储索引(index)中的文档(document)。同一个索引可以存储在不同分片中,这些分片又可以存储在集群中不同节点上。
分片分为主分片(primary shard) 以及从分片(replica shard)
(1)主分片与从分片关系:从分片只是主分片的一个副本,它用于提供数据的冗余副本
(2)从分片应用:在硬件故障时提供数据保护,同时服务于搜索和检索这种只读请求
(3)是否可变:索引中的主分片的数量在索引创建后就固定下来了,但是从分片的数量可以随时改变。
1.3 文档(document)
ES中存储数据的最小单元,在ES的索引中,文档是按照json格式存储。
一个分片可以是主分片或者副本分片。索引内任意一个文档都归属于一个主分片,所以主分片的数目决定着索引能够保存的最大数据量。
一个副本分片只是一个主分片的拷贝。副本分片作为硬件故障时保护数据不丢失的冗余备份,并为搜索和返回文档等读操作提供服务。
在索引建立的时候就已经确定了主分片数,但是副本分片数可以随时修改。
1.4 ES中的数据结构与数据库概念对应关系。
2.ES集群
2.1 集群健康
Elasticsearch的集群监控信息中包含了许多的统计数据,其中最为重要的一项就是集群健康。集群健康存储在status字段中,主要包括green、yellow或者red三种状态。它的三种颜色含义如下:
green
所有的主分片和副本分片都正常运行。
yellow
所有的主分片都正常运行,但不是所有的副本分片都正常运行。
red
有主分片没能正常运行。
2.2 节点扩容
PUT /indexName
{
"settings" : {
"number_of_shards" : 3,
"number_of_replicas" : 1
}
}
上述代码分配3个主分片和一份副本(每个主分片拥有一个副本分片)。下图就是分配好的3个分片被分配到node1节点上。
在上图node1节点的基础上,当第二个节点加入到集群后,3个副本分片将会分配到这个节点上,最终每个主分片对应一个副本分片。这意味着当集群内任何一个节点出现问题时,我们的数据都完好无损。
在主从分片的结构上,所有新近被索引的文档都将会保存在主分片上,然后被并行的复制到对应的副本分片上。这就保证了我们既可以从主分片又可以从副本分片上获得文档。
在实际应用中,随着业务的增长,我们往往会遇到集群性能遇到瓶颈,需要进行节点扩容的操作。例如上述集群有2个节点需要扩容到3个节点。拥有三个节点的集群——为了分散负载而对分片进行重新分配。
Node 1 和 Node 2 上各有一个分片被迁移到了新的 Node 3 节点,现在每个节点上都拥有2个分片,而不是之前的3个。这表示每个节点的硬件资源(CPU, RAM, I/O)将被更少的分片所共享,每个分片的性能将会得到提升。
分片是一个功能完整的搜索引擎,它拥有使用一个节点上的所有资源的能力。 我们这个拥有6个分片(3个主分片和3个副本分片)的索引可以最大扩容到6个节点,每个节点上存在一个分片,并且每个分片拥有所在节点的全部资源。
2.3 故障转移
上述集群中的node1 master主节点发生故障,集群必须拥有一个主节点来保证正常工作,所以发生的第一件事情就是选举一个新的主节点: Node 2。
Node1节点挂机以后,同时也失去了主分片1和2,并且在缺失主分片的时候索引也不能正常工作。 如果此时来检查集群的状况,我们看到的状态将会为 red :不是所有主分片都在正常工作。
幸运的是,在其它节点上存在着这两个主分片的完整副本, 所以新的主节点立即将这些分片在 Node 2 和 Node 3 上对应的副本分片提升为主分片, 此时集群的状态将会为 yellow 。这个提升主分片的过程是瞬间发生的,如同按下一个开关一般。
为什么我们集群状态是 yellow 而不是 green 呢?虽然我们拥有所有的三个主分片,但是同时设置了每个主分片需要对应2份副本分片,而此时只存在一份副本分片。所以集群不能为 green 的状态,不过我们不必过于担心:如果我们同样关闭了 Node 2 ,我们的程序 依然 可以保持在不丢任何数据的情况下运行,因为 Node 3 为每一个分片都保留着一份副本。
3.文档分布式存储
3.1 路由
ES中的文档被均匀的分部到分片上,同时在查询文档的时候会有一个问题:ES如何定位一个文档分布在哪一个分片中呢?以及在创建文档的时候,将文档存放在哪一个分片呢?
ES在进行上述定位时,并不是随机进行操作的,而是按照下面的公式进行路由的。
shard = hash(routing) % number_of_primary_shards
routing 是一个可变值,默认是文档的 _id ,也可以设置成一个自定义的值。routing 通过 hash 函数生成一个数字,然后这个数字再除以 number_of_primary_shards (主分片的数量)后得到 余数 。这个分布在 0 到 number_of_primary_shards-1 之间的余数,就是我们所寻求的文档所在分片的位置。
这就解释了为什么我们要在创建索引的时候就确定好主分片的数量 并且永远不会改变这个数量:因为如果数量变化了,那么所有之前路由的值都会无效,文档也再也找不到了。
3.2 分片交互
假设有一个集群由三个节点组成。 它包含一个索引,有两个主分片,每个主分片有两个副本分片。相同分片的副本不会放在同一节点,如下图所示。
我们可以发送请求到集群中的任一节点。每个节点都有能力处理任意请求。 每个节点都知道集群中任一文档位置,所以可以直接将请求转发到需要的节点上。 在下面的例子中,将所有的请求发送到 Node 1 ,我们将其称为协调节点(coordinating node) 。
以下是从主分片或者副本分片检索文档的步骤顺序:
(1)客户端向 Node 1 发送获取请求。
(2)节点使用文档的 _id 来确定文档属于分片 0 。分片 0 的副本分片存在于所有的三个节点上。在这种情况下,它将请求转发到 Node 2 。
(3)Node 2 将文档返回给 Node 1 ,然后将文档返回给客户端。
在处理读取请求时,协调结点在每次请求的时候都会通过轮询所有的副本分片来达到负载均衡。
在文档被检索时,已经被索引的文档可能已经存在于主分片上但是还没有复制到副本分片。 在这种情况下,副本分片可能会报告文档不存在,但是主分片可能成功返回文档。 一旦索引请求成功返回给用户,文档在主分片和副本分片都是可用的。
3.3 新建、索引和删除文档
新建、索引和删除 请求都是写操作, 必须在主分片上面完成之后才能被复制到相关的副本分片。
以下是在主副分片和任何副本分片上面 成功新建,索引和删除文档所需要的步骤顺序:
(1)客户端向 Node 1 发送新建、索引或者删除请求。
(2)节点使用文档的 _id 确定文档属于分片 0 。请求会被转发到 Node 3,因为分片 0 的主分片目前被分配在 Node 3 上。
(3)Node 3 在主分片上面执行请求。如果成功了,它将请求并行转发到 Node 1 和 Node 2 的副本分片上。一旦所有的副本分片都报告成功, Node 3 将向协调节点报告成功,协调节点向客户端报告成功。
在客户端收到成功响应时,文档变更已经在主分片和所有副本分片执行完成,变更是安全的。