ES原理(转载)
阅读原文时间:2023年07月16日阅读:2

该博客属于转载,是很经典的一篇关于ES的介绍:

Elasticsearch 是一个兼有搜索引擎和NoSQL数据库功能的开源系统,基于Java/Lucene构建,可以用于全文搜索,结构化搜索以及近实时分析。可以说Lucene是当今最先进,最高效的全功能开源搜索引擎框架。 说明: Lucene:只是一个框架,要充分利用它的功能,需要使用JAVA,并且在程序中集成Lucene,学习成本高,Lucene确实非常复杂。 Elasticsearch 是 面向文档型数据库,这意味着它存储的是整个对象或者 文档,它不但会存储它们,还会为他们建立索引,这样你就可以搜索他们了

目录:

  • 应用场景
  • solr VS ES
  • 核心概念
  • ES模块结构
  • 分片示例

应用场景


  • 站内搜索:主要和 Solr 竞争,属于后起之秀

  • NoSQL json文档数据库:主要抢占 Mongo 的市场,它在读写性能上优于 Mongo ,同时也支持地理位置查询,还方便地理位置和文本混合查询,属于歪打正着 (对比测试参见:http://blog.quarkslab.com/mongodb-vs-elasticsearch-the-quest-of-the-holy-performances.html

  • 监控:统计以及日志类时间序的数据的存储和分析以及可视化,这方面是引领者

  • 国外:Wikipedia使用 ES 提供全文搜索并高亮关键字、StackOverflow结合全文搜索与地理位置查询、国内:solr VS ES


    • Solr是Apache Lucene项目的开源企业搜索平台。其主要功能包括全文检索、命中标示、分面搜索、动态聚类、数据库集成,以及富文本(如Word、PDF)的处理。
    • Solr是高度可扩展的,并提供了分布式搜索和索引复制。Solr是最流行的企业级搜索引擎,Solr4 还增加了NoSQL支持。
    • Solr是用Java编写、运行在Servlet容器(如 Apache Tomcat 或Jetty)的一个独立的全文搜索服务器。 Solr采用了 Lucene Java 搜索库为核心的全文索引和搜索,并具有类似REST的HTTP/XML和JSON的API。
    • Solr强大的外部配置功能使得无需进行Java编码,便可对 其进行调整以适应多种类型的应用程序。Solr有一个插件架构,以支持更多的高级定制
    • Elasticsearch 与 Solr 的比较总结

    核心概念


    • 集群(Cluster): 包含一个或多个具有相同 cluster.name 的节点.

    • 节点(node): 一个节点是一个逻辑上独立的服务,可以存储数据,并参与集群的索引和搜索功能, 一个节点也有唯一的名字,群集通过节点名称进行管理和通信.

    • 索引(Index): 索引与关系型数据库实例(Database)相当。索引只是一个 逻辑命名空间,它指向一个或多个分片(shards),内部用Apache Lucene实现索引中数据的读写

    • 文档类型(Type):相当于数据库中的table概念。每个文档在ElasticSearch中都必须设定它的类型。文档类型使得同一个索引中在存储结构不同文档时,只需要依据文档类型就可以找到对应的参数映射(Mapping)信息,方便文档的存取

    • 文档(Document) :相当于数据库中的row, 是可以被索引的基本单位。例如,你可以有一个的客户文档,有一个产品文档,还有一个订单的文档。文档是以JSON格式存储的。在一个索引中,您可以存储多个的文档。请注意,虽然在一个索引中有多分文档,但这些文档的结构是一致的,并在第一次存储的时候指定, 类型(type)索引 中。你也可以通过类比传统的关系数据库得到一些大致的相似之处:

      关系数据库 ⇒ 数据库 ⇒ 表 ⇒ 行 ⇒ 列(Columns)
      Elasticsearch ⇒ 索引 ⇒ 类型 ⇒ 文档 ⇒ 字段(Fields)

    • 模拟示意图如:

    • Mapping: 相当于数据库中的schema,用来约束字段的类型,不过 Elasticsearch 的 mapping 可以自动根据数据创建

    • 分片(shard) :是 工作单元(worker unit) 底层的一员,用来分配集群中的数据,它只负责保存索引中所有数据的一小片。

    ES模块结构


    • 模块结构图如下

    • Gateway: 代表ES的持久化存储方式,包含索引信息,ClusterState(集群信息),mapping,索引碎片信息,以及transaction log等

    • Lucence Directory: 是lucene的框架服务发现以及选主 ZenDiscovery: 用来实现节点自动发现,还有Master节点选取,假如Master出现故障,其它的这个节点会自动选举,产生一个新的Master

    • Discovery

    • memcached

    • River : 代表es的一个数据源,也是其它存储方式(如:数据库)同步数据到es的一个方法。它是以插件方式存在的一个es服务,通过读取river中的数据并把它索引到es中,官方的river有couchDB的,RabbitMQ的,Twitter的,Wikipedia的,river这个功能将会在后面的文件中重点说到

    分片示例


    • 启用一个既没有数据,也没有索引的单一节点, 如下图

    • 在空的单节点集群中上创建一个叫做 blogs 的索引,设置3个主分片和一组从分片(每个主分片有一个从分片对应),代码如下:

      PUT /blogs
      {
      "settings" : {
      "number_of_shards" : 3,
      "number_of_replicas" : 1
      }
      }

    • 集群示例图如下: (此时集群健康状态为: yellow   三个从分片还没有被分配到节点上)

    •    

    • 主分片(primary shards) 启动并且运行了,这时集群已经可以成功的处理任意请求,但是 从分片(replica shards) 没有完全被激活。事实上,当前这三个从分片都处于 unassigned(未分配)的状态,它们还未被分配到节点上。在同一个节点上保存相同的数据副本是没有必要的,如果这个节点故障了,就等同于所有的数据副本也丢失了

    • 启动第二个节点,配置第二个节点与第一个节点的 cluster.name 相同(./config/elasticsearch.yml文件中的配置),它就能自动发现并加入到第一个节点的集群中,如下图:

    •   

    • cluster-health 的状态为 green,这意味着所有的6个分片(三个主分片和三个从分片)都已激活,文档在主节点和从节点上都能被检索

    • 随着应用需求的增长,启动第三个节点进行横向扩展,集群内会自动重组,如图

    • 在 Node 1 和 Node 2 中分别会有一个分片被移动到 Node 3 上,这样一来,每个节点上就都只有两个分片了。这意味着每个节点的硬件资源(CPU、RAM、I/O)被更少的分片共享,所以每个分片就会有更好的性能表现

    • 一共有6个分片(3个主分片和3个从分片),因此最多可以扩展到6个节点,每个节点上有一个分片,这样每个分片都可以使用到所在节点100%的资源了

    • 主分片的数量在索引创建的时候就已经指定了,实际上,这个数字定义了能存储到索引中的数据最大量(具体的数量取决于你的数据,硬件的使用情况)。例如,读请求——搜索或者文档恢复就可以由主分片或者从分片来执行,所以当你拥有更多份数据的时候,你就拥有了更大的吞吐量

    • 从分片的数量可以在运行的集群中动态的调整,这样我们就可以根据实际需求扩展或者缩小规模。接下来,我们来增加一下从分片组的数量:

      PUT /blogs/_settings
      {
      "number_of_replicas" : 2
      }

    • 现在 blogs 的索引总共有9个分片:3个主分片和6个从分片, 又会变成一个节点一个分片的状态了,最终得到了三倍搜索性能的三节点集群

    • 说明:仅仅是在同样数量的节点上增加从分片的数量是根本不能提高性能的,因为每个分片都有访问系统资源的权限。你需要升级硬件配置以提高吞吐量。

    • 尝试一下,把第一个节点杀掉,我们的集群就会如下图所示:

    • 被杀掉的节点是主节点,主分片 1 和 2 在我们杀掉 Node 1 后就丢失了,我们的索引在丢失主节点的时候是不能正常工作的。如果我们在这个时候检查集群健康状态,将会显示 red:存在不可用的主节点

    • 而为了集群的正常工作必须需要一个主节点,所以首先进行的进程就是从各节点中选择了一个新的主节点:Node 2

    • 新的主节点所完成的第一件事情就是将这些在 Node 2 和 Node 3 上的从分片提升为主分片,然后集群的健康状态就变回至 yellow。这个提升的进程是瞬间完成了,就好像按了一下开关

    • 如果再次杀掉 Node 2 的时候,我们的程序依旧可以在没有丢失任何数据的情况下运行,因为 Node 3 中依旧拥有每个分片的备份

    • 如果我们重启 Node 1,集群就能够重新分配丢失的从分片,这样结果就会与三节点两从集群一致。如果 Node 1 依旧还有旧节点的内容,系统会尝试重新利用他们,并只会复制在故障期间的变更数据