Elasticsearch集群架构介绍

集群架构介绍

对于用户来说:elasticsearch是一种去中心化的架构,操作任意节点都是操作操作集群本事,当其中一个节点发生宕机都不会对其他节点产生影响。架构图见下图。
在这里插入图片描述
对于集群本身:elasticsearch节点是有节点区分的分别是Master Node,DataNode,Client Node,对于搜索请求一般是通过ClientNode节点进行处理向DataNode节点获取数据,而索引查询则一般是通过Master节点进行获取。见下图:

在这里插入图片描述

节点介绍

我们讲解一下集群中各节点的作用:

1.MasterNode:可以理解为主节点,对索引的新增,删除,分片,分配,对各个节点的状态进行调度,分发。在整个elasticsearch中可以拥有多个master节点,但是在运行的时候,同一时刻只有一个master节点起作用,当MasterNode节点发生宕机后会从master:true的候选节点中选出一个新的master节点。Master节点它仅仅是对索引的管理、集群状态的管理。像其它的对数据的存储、查询都不需要经过这个Master节点。因此在ES集群中。它的压力是比较小的。所以,我们在构建ES的集群当中,Master节点可以不用选择太好的配置,但是我们一定要保证服务器的安全性。因此,必须要保证主节点的稳定性。

2.DataNode:存储数据的节点,数据的读取、写入最终的作用都会落到这个上面。数据的分片、搜索、整合等 这些操作都会在数据节点来完成。因此,数据节点的操作都是比较消耗CPU、内存、I/O资源。所以,我们在选择data Node数据节点的时候,硬件配置一定要高一些。高的硬件配置可以获得高效的存储和分析能力。因为最终的结果都是需要到这个节点上来。

Client Node:可选节点。作任务分发使用。它也会存储一些元数据信息,但是不会对数据做任何修改,仅仅用来存储。它的好处是可以分担datanode的一部分压力。因为ES查询是两层汇聚的结果,第一层是在datanode上做查询结果的汇聚。然后把结果发送到client Node 上来。Cllient Node收到结果后会再做第二次的结果汇聚。然后client会把最终的结果返回给用户。

其中在配置文件中的表现形式为:

node.master=true	#MasterNodeMaster节点(可配置多个,只代表有参加选举的资格)		默认为true
node.data=true 		#DataNode数据节点	默认为true
node.ingest: true   #ClientNode节点

Elasticsearch集群搭建

请阅读以下文章:

Linux下Elasticsearch,kibana,分词器环境搭建

elasticsearch分片集群搭建

Elasticsearch分片介绍

这里的分片不是我们传统意义上的100分分成4分进行分片存储
这里指的是容器,将文档数据存储在分片上,分片再存储到对应的节点上,当集群需要进行数据迁移,扩容或缩小的时候,只用移动分片就行。

分片可以是主分片(primary shard)或者是复制分片(replica shard)。

设置节点分片语法

curl -H "Content-Type: application/json" -XPUT 192.168.3.191:9200/"节点名称"-d '
{
   "settings": {
       "number_of_shards": 3,		#主分片数量=集群数量
       "number_of_replicas": 2		#分片数量。一般为number_of_shards-1
   }
}

这里设置number_of_shards-1是因为大于这个数量会设置超过集群的分片数量,一个服务器就会承载多余的相同分片没有实际意义,倘若小于这个数量就会造成服务器有一些没有备份到。

主分片

主分片:主要的数据读写分片,写入数据,产生多个分片的时候,通过路由确定分片的位置。主要算法如下

shard = hash(routing) % number_of_primary_shards 3

routing 是一个可变值,默认是文档的 _id ,也可以设置成一个自定义的值。routing 通过 hash 函数生成一个数字,然后这个数字再除以 number_of_primary_shards (主分片的数量)后得到余数 。这个在 0 到 number_of_primary_shards 之间的余数,就是所寻求的文档所在分片的位置。

我们设置好分片数量后不要去修改分片,因为当分片重新修改后,以前存储的数据地址存储就找不到了。造成数据丢失。

复制分片

复制分片只是主分片的一个副本,它可以防止硬件故障导致的数据丢失,同时可以提供读请求,比如搜索或者从别的 shard 取回文档。每个主分片都有一个或多个副本分片,当主分片异常时,副本可以提供数据的查询等操作。主分片和对应的副本分片是不会在同一个节点上的,所以副本分片数的最大值是 n -1(其中 n 为节点数)。

当索引创建完成的时候,主分片的数量就固定了,但是复制分片的数量可以随时调整,根据需求扩大或者缩小规模。如把复制分片的数量从原来的 1 增加到 2 :

192.168.3.195:9200/"节点名称"/_settings -d '
{
   "number_of_replicas": 2
}'

Elasticsearch存储原理

写索引过程

ES 集群中每个节点通过路由都知道集群中的文档的存放位置,所以每个节点都有处理读写请求的能力。
在一个文档数据写到某一个节点上时,该节点就为协调节点,该节点会通过路由计算好的分片的地址将请求转发到对应的节点上,并通过乐观锁的方式将复制节点的数据写入进去。原理图如下:
在这里插入图片描述
虚线部分为同步复制节点,通过乐观锁进行写入。

段的引入

在上面我们说了分片的索引不能进行修改,那么我修改文档数据时,肯定会将以前的索引标记为过期的,然后更新一条新的索引,比如一个文档有1000个索引,修改1个数据,那么肯定会将1000个索引标记为过期等着GC,并新建1000个索引,这个效率肯定是低下的。

为了解决这个问题,在ES中采用了2个方法,一个是倒排索引,即把分词的索引地址存储在一起,eg: “关键词1”:“文档1”的ID,“文档2”的ID,…………。“关键词2”:带有此关键词的文档ID列表。

另外就是段的引入了。什么是段?分片下的索引文件被拆分为多个子文件,每个子文件叫作段, 每一个段本身都是一个倒排索引,并且段具有不变性,一旦索引的数据被写入硬盘,就不可再修改。

段的创建过程:

1.新的文档首先写入内存区的索引缓存,这时不可检索。
2.时不时(默认 1s 一次),内存区的索引缓存被 refresh 到文件系统缓存(该过程比直接到磁盘代价低很多),成为一个新的段(segment)并被打开,这时可以被检索。
3.新的段提交,写入磁盘,提交后,新的段加入提交点,缓存被清除,等待接收新的文档。

见下图:
在这里插入图片描述
1.在内存的时候只有写入的权限,不具备读取数据的权限。
2.当在文件系统缓存阶段,当存满了或者其他某一条件触发了才会写入磁盘,并生成一个commit point提交点。提供读的
3.磁盘阶段只有读的权限,不具备读取的权限。

倒排排序和段的引入就解决了频繁修改文件,导致内存磁盘大规模的IO读写的性能问题。那么具体是如何解决的呢?

新增文档:新增一个段,方法文件系统,最后写入文档。
删除文档:在段中添加.del标记文件,包含了删除的文档,但它实际上并非在当前段中删除掉,而是查询的时候排序掉这些标记了文档,逻辑删除。
更新:因为不能使用更改文档索引,所以这里是用删除和新增2个步骤完成的。当老文档标记了.del后会新增一个新版本的段,读取到2个版本的段,排除掉旧版本的段。

索引不可变的优劣

好处:

  • 不需要锁。因为如果从来不需要更新一个索引,就不必担心多个程序同时尝试修改,也就不需要锁。
  • 一旦索引被读入内核的文件系统缓存,便会留在哪里,由于其不变性,只要文件系统缓存中还有足够的空间,那么大部分读请求会直接请求内存,而不会命中磁盘。这提供了很大的性能提升。
  • 在生命周期内始终有效。它们不需要在数据发生变化时被重建。

坏处:

  • 当对旧数据进行删除时,旧数据不会马上被删除,而是在 .del 文件中被标记为删除。而旧数据只能等到段更新时才能被移除,这样会造成大量的空间浪费。
  • 更新时也会造车空间的浪费
  • 每次新增都是一个新的段,当段多时,对查询也不友好。
  • 查询的时候需要清理删除的文档,增加查询负担

持久化

前面说到了会存在文件系统内存中,文件系统内存也是内存不过是内核内存,是内存遇上断电肯定会发生数据丢失呢,那么ES是如何做数据持久化呢?

1.写入数据,先写入内存,写入内存的同时写入log日志文件。
2.一秒一次,刷入段中,提供读的功能
3.段到达一定体量时清空段,写入磁盘,完成commit point点,清空日志文件

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐