Elasticsearch基本概念和原理

631 阅读6分钟

Elasticsearch基本介绍

  • ES是什么?

    ES是一款基于Apache Lucene的开源分布式搜索引擎

  • 应用场景

    • 日志记录与分析(接口调用情况)
    • 采集和组合公共数据(用户行为、点击事件)
    • 全文检索
    • 数据可视化(通过Kibana)
  • 逻辑与物理设计

    首先看一些概念:

    • 集群cluster

      ES是分布式的,多个节点构成一个集群,并且集群也是可扩展的

    • 节点node

      每个启动的ES实例就是一个节点,可以随时加入或者脱离集群

    • 索引index

      名词:一堆字段相似的文档的集合,类比MySQL的一张表

      动词:将文档写入某个索引

    • 文档document

      一条ES的记录,类比MySQL的一行数据

    • 分片shard

      • 分片是ES所能管理的最小单元
      • 一个分片就是一个Lucenne索引
      • 一个包含倒排索引的文件目录
      • 分片越多(过度分片),搜索有可能越慢
    • 分段segment

      • lucene索引再分割的小单元

      • 分段不会被修改

      • 分段越多,搜索越慢

      • 索引新的文档会创建新的分段

      • 分段会被持续地合并

      • 删除文档的时候不会真的删除(只是设置了标记)

扩展与容灾

分片:扩展与容灾

首先,一个索引地所有分片会自动均匀地分布在所有节点中。当我们加入一个新节点后,如下图所示,原集群节点中地分片,有部分会迁移到新节点。

注:设置分片数量稍微大于节点数量,有利于横向扩容时,分片蔓延到所有新节点,如图一所示,就是一个index包含四个分片,而es集群中有三个节点,新加入节点后可以蔓延(最理想的状态就是每个节点都有分片)。但是蔓延的过程是有一定消耗的,所以会对集群产生一些抖动的。此外,当主分片和所有副本分片都就绪时,索引地健康状态是绿色

我们在Kibana的monitoring组件上可以看见分片的活跃程度。

接下来我们来分析容灾,如下图所示为在图1的基础上挂掉一个节点的示意图。

  • 当挂掉了N个节点时,如果副本分片是N,那么剩下的副本分片将 自动提升为主分片。
  • 然后所有的主分片能构成完整的索引,但是副本分片缺失时,此时索引健康状态是黄色。
  • 如果挂掉N+1个节点,主分片将缺失,健康状态是红色。
  • 我们需要根据实际情况合理的设置副本的数量(副本太多也会影响性能)
  • 通常同时挂掉两个节点的概率不高,一般来说一个副本可以满足常规容灾要求。

索引和搜索数据

索引请求如下图所示:

  • 具体过程

    • 索引文档请求到一个节点
    • 文档会被随机到一个主分片上
    • 从主分片同步到副本分片
    • 返回成功的结果

    注:副本分片越多,索引数据越慢,因为要所有副本都完成才算成功

再来看搜索过程,如下图所示:

  • 具体过程

    • 搜索请求到一个节点
    • 节点转发请求到本节点的一个分片和其他节点的另一个分片
    • 所有的分片都返回搜索结果到起始节点,但是只要有一个shard搜索到了数据就会立刻返回
    • 起始节点返回搜索结果到请求方

    注:不同节点的主分片+副本分片的总数越多,请求被分摊的越 多,并发搜索兴能越好。但是如果节点数很少,分片都集中到了少数节点上,搜索速度会变慢,因为增加了开销,实际没有分摊负载。此外,单个搜索没有办法通过分片加速。

分段

  • 写入

    • 只能写打开的分段(为了避免冲入合并)
    • 删除是假的删除,也是往打开的分段里写标志位(这是为了保证随机读写)
    • 分段大小超过一定阈值,会触发分段合并
    • 小分段合并成大分段,为了查询加速,但合并过程是先创建一个大分段,再把两个小的放进去,再删除这两个小的,但这个过程会耗费大量资源
    • 如果希望写入快,就要避免频繁的分段合并
  • 读取

    • 只能读取关闭的分段(所以ES叫准实时,关闭这个过程也叫做刷新)
    • 对一个分片查询,会等它所有的分段返回结果,所以分段过多,查询越慢
    • 刷新时,会关闭一批分段,这时候数据才能被查到
    • 刷新频率太快会导致分段碎片多
    • 刷新频率过慢会导致实时性低

总结一下,我们可以看到,如果我们追求的是写入更快的话,我们就要尽力的避免频繁的分段合并,保留相对多一点的分段;但是如果我们要追求读取性能的话又要考虑减少分段,这也就是鱼和熊掌的问题了,需要我们结合实际业务场景进行分析。

在Kibana中我们可以设置刷新的频率、副本数量等等参数

一些问题

  • 那么索引分片不是免费的吗/分片越多越好吗?

    • 每个索引和分片都会产生一定的资源开销,尤其是内存资源

    • 每个索引,映射和状态的信息都存储在集群中

      • 存储在内存中,以便快速访问
      • 分片数量过多,会导致集群状态过大
      • 这会导致更新变慢,因为所有的更新都是通过单线程来完成的,从而这是在将变更分发到整个集群之前确保一致性的前提
    • 分片有一部分数据需要保存在内存中

      • 这部分数据也会占据堆内存空间
      • 这包括存储分片级别以及段级别信息的数据结构
      • 因为只有这样才能确定数据在磁盘上的存储位置
    • 那怎么样在单个节点上存储尽可能多的数据呢?

      • 管理堆内存使用量
      • 尽可能减少开销
      • 节点的堆内存空间越多,能处理的数据和分片就越多
      • 官方建议:JVM heap每1G不超过20个分片,每个分片大小在20G

参考连接