基本概念

  • 文档型存储的中间件
  • 以JSON格式进行数据存储
  • 支持对文档数据的增删改查,即CRUD操作。即CRUD操作。
  • 使用了分片和复制技术,支持处理超大规模数据。
  • 基于Java编写
  • Elasticsearch基于Hash模式进行分片
  • 集群的配置方式: Elasticsearch天然是分布式的,主副分片自动分配和复制
  • 全文检索: Elasticsearch全文检索功能强大,字段自动索引
  • Elasticsearch适合用于搜索以及存储日志数据(全文检索),但数据并非实时,却决于refresh_interval参数的配置

集群中概念

  • 集群(cluster): 由一个或多个节点组成, 并通过集群名称与其他集群进行区分

  • 节点(node): 单个 ElasticSearch 实例. 通常一个节点运行在一个隔离的容器或虚拟机中

  • 索引(index): 在 ES 中, 索引是一组文档的集合

  • 分片(shard): 因为 ES 是个分布式的搜索引擎, 所以索引通常都会分解成不同部分, 而这些分布在不同节点的数据就是分片. ES自动管理和组织分片, 并在必要的时候对分片数据进行再平衡分配, 所以用户基本上不用担心分片的处理细节.

  • 副本(replica): ES 默认为一个索引创建 5 个主分片, 并分别为其创建一个副本分片. 也就是说每个索引都由 5 个主分片成本, 而每个主分片都相应的有一个 copy。对于分布式搜索引擎来说, 分片及副本的分配将是高可用及快速搜索响应的设计核心.主分片与副本都能处理查询请求,它们的唯一区别在于只有主分片才能处理索引请求.副本对搜索性能非常重要,同时用户也可在任何时候添加或删除副本。额外的副本能给带来更大的容量, 更高的呑吐能力及更强的故障恢复能力。

  • 在创建索引的时候就确定好主分片的数量 并且永远不会改变这个数量:因为如果数量变化了,那么所有之前路由的值都会无效,文档也再也找不到了

关于分片配置

分配分片时主要考虑数据集的增长趋势.

要知道, 分配的每个分片都是有额外的成本的:

  • 每个分片本质上就是一个Lucene索引, 因此会消耗相应的文件句柄, 内存和CPU资源
  • 每个搜索请求会调度到索引的每个分片中. 如果分片分散在不同的节点倒是问题不太. 但当分片开始竞争相同的硬件资源时, 性能便会逐步下降
  • ES使用词频统计来计算相关性. 当然这些统计也会分配到各个分片上. 如果在大量分片上只维护了很少的数据, 则将导致最终的文档相关性较差

如果真的担心数据的快速增长, 建议多关心这条限制: ElasticSearch推荐的最大JVM堆空间是30~32G, 所以把你的分片最大容量限制为30GB, 然后再对分片数量做合理估算. 例如, 数据能达到200GB, 推荐最多分配7到8个分片.

总之, 不要现在就为可能在三年后才能达到的10TB数据做过多分配. 如果真到那一天, 也会很早感知到性能变化的.

在开始阶段, 一个好的方案是根据你的节点数量按照1.5~3倍的原则来创建分片. 例如,如果有3个节点, 则推荐创建的分片数最多不超过9(3x3)个.

但每个索引的数据量只有1GB甚至更小. 对于这种类似场景, 建议只需要为索引分配1个分片.

如果使用ES的默认配置(5个分片), 并且有基于日期的索引需求, 那么6个月下来, 拥有的分片数将达到890个. 再多的话, 集群将难以工作--除非提供了更多(例如15个或更多)的节点.

分片副本

分片

  • 分片是Elasticsearch索引的数据块。Elasticsearch会将每个索引划分为多个分片,分布在不同节点上。
  • 分片的好处是可以支持水平扩展,提高查询效率。比如一个索引有3个主分片,此时每个节点可以存储部分数据。
  • 我们可以在创建索引时就预先设置主分片数量,默认是5个,但数量不可变更。

副本

  • 副本是主分片的一个完整拷贝,它可以提供冗余,防止主分片损坏的情况。
  • 我们可以设置每个主分片的副本数量,默认是1个。副本可以动态调整。
  • 副本会与主分片均衡分布在不同节点。

一个主两从的集群

对于一个3节点的集群,可以这样配置:

  • 设置索引分片数为6个(大于节点数)
  • 设置副本数为1(默认值)

这样的好处是:

  • 数据可以均衡分布,充分利用三个节点
  • 即使一个节点宕机,也有冗余副本可以继续提供服务

当然也可以根据实际情况调整分片和副本数量,要根据数据量、查询负载等因素进行测试。

ES各种节点的分工

  • 客户端节点

  当主节点和数据节点配置都设置为false的时候,该节点只能处理路由请求,处理搜索,分发索引操作等,从本质上来说该客户节点表现为智能负载平衡器。独立的客户端节点在一个比较大的集群中是非常有用的,他协调主节点和数据节点,客户端节点加入集群可以得到集群的状态,根据集群的状态可以直接路由请求。

  • 数据节点

  数据节点主要是存储索引数据的节点,主要对文档进行增删改查操作,聚合操作等。数据节点对cpu,内存,io要求较高, 在优化的时候需要监控数据节点的状态,当资源不够的时候,需要在集群中添加新的节点。

  • 主节点

  主资格节点的主要职责是和集群操作相关的内容,如创建或删除索引,跟踪哪些节点是群集的一部分,并决定哪些分片分配给相关的节点。稳定的主节点对集群的健康是非常重要的,默认情况下任何一个集群中的节点都有可能被选为主节点,索引数据和搜索查询等操作会占用大量的cpu,内存,io资源,为了确保一个集群的稳定,分离主节点和数据节点是一个比较好的选择.

建议

在一个生产集群中我们可以对这些节点的职责进行划分,建议集群中设置3台以上的节点作为master节点,这些节点只负责成为主节点,维护整个集群的状态。再根据数据量设置一批data节点,这些节点只负责存储数据,后期提供建立索引和查询索引的服务,这样的话如果用户请求比较频繁,这些节点的压力也会比较大,所以在集群中建议再设置一批client节点(node.master: false node.data: true),这些节点只负责处理用户请求,实现请求转发,负载均衡等功能。

集群脑裂问题

集群职责划分

elasticsearch中集群节点有不同的职责划分:

默认情况下,集群中的任何一个节点都同时具备上述四种角色。

但是真实的集群一定要将集群职责分离:

  • master节点:对CPU要求高,但是内存要求第
  • data节点:对CPU和内存要求都高
  • coordinating节点:对网络带宽、CPU要求高

职责分离可以让我们根据不同节点的需求分配不同的硬件去部署。而且避免业务之间的互相干扰。

一个典型的es集群职责划分如图:

脑裂问题

脑裂是因为集群中的节点失联导致的。

例如一个集群中,主节点与其它节点失联:

此时,node2和node3认为node1宕机,就会重新选主:

当node3当选后,集群继续对外提供服务,node2和node3自成集群,node1自成集群,两个集群数据不同步,出现数据差异。

当网络恢复后,因为集群中有两个master节点,集群状态的不一致,出现脑裂的情况:

解决脑裂的方案是,要求选票超过 ( eligible节点数量 + 1 )/ 2 才能当选为主,因此eligible节点数量最好是奇数。对应配置项是discovery.zen.minimum_master_nodes,在es7.0以后,已经成为默认配置,因此一般不会发生脑裂问题

例如:3个节点形成的集群,选票必须超过 (3 + 1) / 2 ,也就是2票。node3得到node2和node3的选票,当选为主。node1只有自己1票,没有当选。集群中依然只有1个主节点,没有出现脑裂。

小结

master eligible节点的作用是什么?

  • 参与集群选主
  • 主节点可以管理集群状态、管理分片信息、处理创建和删除索引库的请求

data节点的作用是什么?

  • 数据的CRUD

coordinator节点的作用是什么?

  • 路由请求到其它节点

  • 合并查询到的结果,返回给用户

集群分布式存储

当新增文档时,应该保存到不同分片,保证数据均衡,那么coordinating node如何确定数据该存储到哪个分片呢?

分片存储测试

插入三条数据:

测试可以看到,三条数据分别在不同分片:

结果:

分片存储原理

elasticsearch会通过hash算法来计算文档应该存储到哪个分片:

说明:

  • _routing默认是文档的id
  • 算法与分片数量有关,因此索引库一旦创建,分片数量不能修改!

新增文档的流程如下:

解读:

  • 1)新增一个id=1的文档
  • 2)对id做hash运算,假如得到的是2,则应该存储到shard-2
  • 3)shard-2的主分片在node3节点,将数据路由到node3
  • 4)保存文档
  • 5)同步给shard-2的副本replica-2,在node2节点
  • 6)返回结果给coordinating-node节点

集群分布式查询

elasticsearch的查询分成两个阶段:

  • scatter phase:分散阶段,coordinating node会把请求分发到每一个分片

  • gather phase:聚集阶段,coordinating node汇总data node的搜索结果,并处理为最终结果集返回给用户

集群故障转移

集群的master节点会监控集群中的节点状态,如果发现有节点宕机,会立即将宕机节点的分片数据迁移到其它节点,确保数据安全,这个叫做故障转移。

1)例如一个集群结构如图:

现在,node1是主节点,其它两个节点是从节点。

2)突然,node1发生了故障:

宕机后的第一件事,需要重新选主,例如选中了node2:

node2成为主节点后,会检测集群监控状态,发现:shard-1、shard-0没有副本节点。因此需要将node1上的数据迁移到node2、node3: