ElasticSearch概念与架构原理

Posted @@神农写代码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ElasticSearch概念与架构原理相关的知识,希望对你有一定的参考价值。

文章目录

一、概述

  • ElasticSearch简介
    • 简介
      • ES是建立在Lucene基础之上的分布式准实时搜索引擎,它所提供的诸多功能中有一大优点,就是实时性好。比如:在业务需求中,新增数据需要1min才能被搜索到,而在ES中数秒或1s内就能搜索到新增的数据。
      • ES不仅是一个搜索引擎框架,而且官方还提供了一个全家桶,为构建搜索引擎提供了很好的解决方案,就是ELK:
        • E:ElasticSearch:提供数据搜索和分析功能
        • L:Logstash:借助它可以将数据库和日志等结构化或非结构化的数据轻松的导入到ES中
        • K:Kibana:可已经分析结果进行图形化展示出来
    • 特性
      • 实时性好
      • 可以分布式部署ES
      • 可以通过Http请求使用REST风格API接口的方式对ES执行请求完成搜索任务
      • ES 还提供了聚合的功能,可以对数据进行统计分析
      • 在数据安全方面ES还提供了X-Pack进行用户验证
  • ElasticSearch基本概念
    • 索引

      • 在传统的关系型数据库中,我们对数据进行操作[CURD],需要建一个库,而ES中的需要建索引,对数据的操作的对象全部对应索引。ES中的一个索引对应一个或者多个Lucene索引,这是由分布式设计方案决定的。
    • 文档

      • 在传统的关系型数据库中,需要将数据封装成数据库中的一条记录,而在ES中是对应是文档。ES的文档中可以有多个字段,每个字段建议是各种数据类型。为了减轻集群的堵在和提升效率,ES提供了文档的批量索引、更新和删除功能。
    • 字段

      • 一个文档中可以包含多个字段,每个字段有一个数据类型与其对应。除了常用的数据类型(字符串、文本和数值)外,ES还提供了多种数据类型,如:数组类型、经纬度、IP地址类型等。ES对不同类型的字段可以支持不同的搜索功能。例如:使用文本类型的数据时,可以按照分词的方式对数据进行搜索,并且可以对设定搜索后的打分因子来影响最终的排序;再如:使用经纬度数据时,ES可以搜索某个地点附近的文档,也可以查询地理围栏内的文档。在排序函数上ES也可以基于某个地点按照衰减函数进行排序。

        索引、文档和字段的关系,如图:

    • 映射

      • 建立索引使需要定义文档的数据结构,这种结构叫做映射。在映射中,文档中的字段的数据类型设定后不能在进行更改。因为字段类型在定义后,ES已经定义的类型建立了特定的索引结构,这种结构不能更改。借助映射可以给文档新增字段。另外,ES还提供了自动映射的功能,在添加数据时,如果该字段没有定义类型,ES会根据用户提供的该字段的真实数据来猜测可能的类型,从而自动进行字段类型的定义。
    • 集群与节点

      • 在分布式系统中,为了完成海量数据的存储、计算并提升系统的高可用性,需要多台计算机集成协作,这种形式称之为集群。这些集群中的每个计算机我们又称之为节点。ES集群的节点个数是没有限制的,用户可以根据业务量、数据量增加节点,如图:

    • 分片

      • 在分布式系统中,为了能存储和计算海量数据,会对数据进行分片,将数据存储在不同的计算机中。在ES中一个分片对应一个Lucene索引,每个分片下面还可以设置多个副分片。索引的分片个数只能设置一次,之后不能在更改,默认情况下每个索引设置5个分片。

      • 优点

        • 分担集群的存储和计算压力
        • 提高系统中数据的高可用性
        • 每一个分片可以设置多个副分片当主分片所在的计算机因某些原因离线时,副分片可以充当主分片继续服务
    • 副分片

      • 为了提升系统索引数据的高可用性和减轻集群搜索的负载,可以启用分片的副本,副本我们称之为副分片。在一个索引中,主分片的副分片的个数是没有限制的,用户可以按需设定。在默认情况下,ES不会为主分片开启副分片,需要手动进行设置。一个分片的主分片和副分片可以存储在不同的计算机上,如图:

      • 注意事项

        • 在极端情况下,当只有一个节点时,如果索引的副分片个数设置大于1,则系统只分配主分片,而不会设置副分片。
    • DSL

      • ES使用DSL[Domain Specific Language]来定义查询,常见的 html/css/sql都属于DSL。ES中的DSL采用json的方式来表达,客户端接受的数据也是封装好的json形式;优点:可以简单明了的表达请求/响应内容,而且还屏蔽各种编程语言之间数据通信的差异。
  • ElasticSearch与其他数据库对比
    类型ElasticSearch关系型数据库
    索引方式正排索引和倒排索引B-Tree结构
    事务支持不支持事务[更新文档时,先读取在更新,如果并发修改数据,使用乐观锁]支持事务
    SQL与DSL查询、大小、相等比较、逻辑、或、与、关系运算,文本搜索、地理位置搜索和复杂数据的搜索查询、大小、相等比较、逻辑、或、与、关系运算
    扩展方式本身支持分片和副分片需要借助第三方组件进行分库分表,分库分表会对一些业务造成延迟,查询结果的合并和多表join的操作
    数据的查询速度ES是基于Lucene库的搜索引擎,可以支持全字段建立索引,单个索引存储上百个字段或几十亿条数据记录都是没有问题的,查询速度也不会变慢字段数量与数据量过大查询速度很慢
    数据的实时性为了提高写入数据的性能,ES在内存和磁盘之间增加一层系统缓存,ES响应写入数据的请求后,会将数据存储到内存中,此时该数据还不能搜索到,内存中的数据每隔一段时间会被刷新到系统缓存内,此时的数据才能被搜索到。因此,ES的写入数据不是实时的,而是准实时的。存储和查询数据基本上是实时的,即单条数据的写入可以立即查询

二、ElasticSearch架构原理

  • 节点职责

    • 节点职责类型

      • master节点

        • master节点负责维护整个集群的相关工作,管理集群的变更,如创建/删除索引、节点健康监测、节点上/下线等。maste节点是由集群节点通过选举算法选举出来的,一个集群中只有一个节点为master节点,但是可以有一个或多个节点参与master节点的选举,在默认情况下,任意节点都可以作为master候选节点,可以通过配置项node.master对当前节点是否作为master候选节点进行控制。
      • 数据节点

        • 数据节点主要负责索引数据的保存工作,此外也执行数据的其他操作,如文档删除、修改和查询操作。数据节点的很多工作是调用Lucene库进行Lucene索引操作,因此这种节点对内存和I/O的消耗比较大,生产环境中应多注意数据节点的计算机负载情况。
      • 协调节点

        • 客户端可以向ES集群的节点发起请求,这个节点叫做协调节点。在默认情况下,协调节点可以是集群中的任意节点,此时他的生命周期是和一个单独的请求相关的。也就是说当客户端向集群中的某个节点发起请求时,此时该节点被称为当前请求的协调节点,当它将响应结果返回客户端后,该协调节点生命周期就结束了。如图所示,分别表示访问不同的节点,因为请求时客户端指定的请求地址不同,所以左图中的请求协调节点时node1,右图中的请求协调节点时node3。协调节点会根据具体的情况将请求转发给其他节点,并将最终汇总的处理结果返回客户端;


      为了降低集群的负载,可以将某个节点作为单独的协调节点。在节点的配置文件中设置node.maste和node.data配置项为false,此时这个节点不会选中master节点并且不在担任数据节点,而客户端可以将这类节点作为协调节点来使用,把所有的请求分发到这些节点上,如图:

    • 每个节点可以单独配置,默认情况下集群不会对节点角色进行划分,所有的节点都是相互平等的,可以担任所有的职责。但是在生产环境中需要对这些节点的角色进行最优的划分,否则在高并发的情况下集群容易出现服务阻塞超时甚至服务崩溃的隐患。

  • 主分片和副分片

    • ES为了支持分布式搜索,会把数据按照分片进行切分。一个索引由一个或者多个分片构成,并且每个分片有0个甚至多个副分片。多个分片可以分布在不同的节点中,通过这种方式提高分片数据的高可用性和服务的高并发支持。

    • 集群中的索引主分片和副分片在不同的计算机上,如果某个主分片所在的节点宕机,则原有的某个副分片会提升为主分片进行对外服务,如图:

      如果node1发生了宕机,集群感知到分片0的主分片A0将要丢失,此时集群会立即对其他节点[node3]上的分片0对应的副分片C0作为主分片A0进行服务,集群中的node2和node3对外提供服务,所有的分片服务不受影响;如图:

    如果node1恢复了服务并加入了集群中,因为在node1上还保留有分片0的数据,此时node1上的分片A0会变成副分片C0。在此期间丢失的数据会通过node3上的主分片A0进行补充。并且node1上的分片也会通过node2和node3对应的分片进行补充数据。

    • 当客户端对某个索引的请求被分发到ES的协调节点时,协调节点会将请求进行转发,转发的对象时包括这个索引的所有分片的部分节点。协调节点中有一份分片-节点路由表,该表主要存放分片和节点的对应关系。协调节点会用轮询的算法,选取该索引的主/副分片所在的节点进行请求转发。一个索引的主分片设定后就不能修改,如果想提升索引的并发性可以增加副分片的数量,此时协调节点会将这些副分片加入到轮询算法中。
  • 路由计算

    • 当客户端向一个ES的协调节点发送请求时,协调节点是如何将数据存储在哪个节点的哪个分片上?

      • 根据hash算法,公式如下:

        shard = hash(routing)%number_of_prinary_shards
        #routing :每条文档的提交是的参数,该值是可变的,用户可以自定义,在默认情况下使用的是文档的_id值
        #number_of_prinary_shards:索引主分片的个数
        

    计算出routing值后除以索引主分片的个数在取余,就是当前文档应该存储的分片ID。

    获取分片ID后,根据分片-节点路由表获取该分片的主/副分分片节点列表,然后在转发请求。

    通过上面的公式number_of_primary_shards主分片作为取余的分母不能随意改变,否则分片ID将会计算错误,进而找不到存储数据的分片节点。

  • 文档读写过程

    • 写入

      • 当ES的协调节点收到来自客户端写入数据的请求时,协调节点会根据路由算法算出将文档写入到主分片上,然后将请求转发给分片所在节点上,完成数据存储后,该节点会将请求转发给该分片的其他副分片所在的节点,直到副分片节点完全写入成功,ES协调节点向客户端返回成功信息,如图:

      • 假如:我们的集群中有三个节点,索引有三个主分片和六个副分片,当客户端发送写入数据请求到节点1,假设节点1为协调节点,根据路由算法算出将数据写入到分片1上,由于分片1的主分片在节点2上,则会将请求转发给节点2,节点接收到客户端的数据并完成存储,再将请求转发给副分片1所在的节点1和节点3上,当所有的副分片完成数据存储后,协调节点再向客户端返回成功标志。
    • 读取

      • 当ES协调节点收到客户端发来的查询文档请求,协调节点会根据文件找到所有的分片,根据轮询算法从主/副分片中选一个分片,然后将请求转发给该分片所在的节点,该节点完成请求后并将目标数据返回给协调节点,协调节点再将数据返回给客户端,如图:

        当客户端发起查询请求到节点1[协调节点],协调节点会根据文档找到所有的分片,使用轮询算法从主/副分片中选一个分片,假如在节点3中的副分片1中,完成请求后节点3将目标数返回给节点1,节点1再将数据返回给客户端。

三、ElasticSearch搜索入门

  • 创建索引 使用 postman创建索引
    //在postman输入ES地址:http://localhost:9200/[索引名称]
    //访问方式为:PUT
     
        "mappings": 
            "properties":           //指定字段名称及其数据类型 
                "title": 
                    "type":"text"    //title字段为text类型 
                , 
                "city": 
                   "type":"keyword"   //city字段为keyword类型 
                , 
                "price": 
                    "type":"double"   //price字段为double类型 
                 
             
         
    
    
    • 写入文档
      //在postman输入ES地址:http://localhost:9200/[索引名称]/_doc/[id编号]
      //访问方式为:Post
       
      "title":"好再来酒店", 
      "city":"青岛", 
      "price":578.23 
      
      
  • 根据_Id搜索文档
    //在postman输入ES地址:http://localhost:9200/[索引名称]/_doc/[id编号]
    //访问方式为:Get
     
     "_index" : "hotel",                  //索引名称 
      "_type" : "_doc", 
     "_id" : "001",                       //文档ID 
     "_version" : 1,                      //文档版本 
      "_seq_no" : 0, 
      "_primary_term" : 1, 
      "found" : true, 
     "_source" :                         //文档内容 
        "title" : "好再来酒店", 
        "city" : "青岛", 
        "price" : 578.23 
       
    
    
  • 根据一般字段搜索文档
    • 在ES中进行搜索时需要用到query子句,代码如下
    //在postman输入ES地址:http://localhost:9200/[索引名称]/_search
    //访问方式为:Get
    
      "query": //查询内容
         .........
       
    
    //例如:
    
      "query":
         "price":
               "value":578.23 
           
       
    
    //查询结果如下:
     
      "took" : 1, 
      "timed_out" : false, 
     "_shards" :        //命中的分片信息 
        "total" : 1, 
        "successful" : 1, 
        "skipped" : 0, 
        "failed" : 0 
      , 
      "hits" :   
       "total" :                          //命中的文档总数 
          "value" : 1, 
          "relation" : "eq" 
        , 
       "max_score" : 1.0,                  //命中文档中的最高分
       "hits" : [                          //命中文档集合的信息
           
            "_index" : "hotel",            //文档所在索引 
            "_type" : "_doc",   
            "_id" : "001",                //文档ID 
            "_score" : 1.0,               //文档分值 
            "_source" :                  //文档内容 
              "title" : "好再来酒店", 
              "city" : "青岛", 
              "price" : 578.23 
             
           
        ] 
       
    
    
  • 根据文本字段搜索文档
    • 前面的搜索功能在传统的关系型数据库中也可以胜任,但是对文本进行模糊匹配并给出匹配分数这一功能是搜索引擎独有的,此时使用match搜索对某个字段进行模糊匹配,代码如下:
    //在postman输入ES地址:http://localhost:9200/[索引名称]/_search
    //访问方式为:Get
    
       "query":
         "match":
            "title":"再来"
          
       
    
    //查询结果:
    "max_score" : 0.5753642,                     //命中文档中的最高分 
       "hits" : [                                    //命中文档集合的信息 
            
            "_index" : "hotel", 
            "_type" : "_doc", 
            "_id" : "001", 
            "_score" : 0.5753642, 
            "_source" :  
              "title" : "好再来酒店", 
              "city" : "青岛", 
              "price" : 578.23 
             
           
        ] 
       
    
    

ElasticSearch学习总结:ES介绍与架构说明

本文主要从概念以及架构层面对Elasticsearch做一个简单的介绍,在介绍ES之前,会先对ES的“发动机”Lucene做一个简单的介绍

1. Lucene介绍

为了更深入地理解ElasticSearch的工作原理,特别是索引和查询这两个过程,理解Lucene的工作原理至关重要。本质上,ElasticSearch是用Lucene来实现索引的查询功能的。

1.1 定义

Lucene是一个成熟的、高性能的、可扩展的、轻量级的,而且功能强大的搜索引擎包。Lucene的核心jar包只有一个文件,而且不依赖任何第三方jar包。更重要的是,它提供的索引数据和检索数据的功能开箱即用。当然,Lucene也提供了多语言支持,具有拼写检查、高亮等功能。

1.2 架构

1.2.1 术语

Lucene中的术语和 <

1.2.2 存储

Apache Lucene把所有的信息都写入到一个称为倒排索引的数据结构中,倒排索引的介绍可以参考 <

1.3 数据分析

学习ES初期,我经常考虑的问题是,传入到Document中的数据是如何转变成倒排索引的?查询语句是如何转换成一个个Term使高效率文本搜索变得可行?这种转换数据的过程就称为文本分析(analysis)

文本分析工作由analyzer组件负责。analyzer由一个分词器(tokenizer)和0个或者多个过滤器(filter)组成,也可能会有0个或者多个字符映射器(character mappers)组成。

Lucene中的tokenizer用来把文本拆分成一个个的Token。Token包含了比较多的信息,比如Term在文本的中的位置及Term原始文本,以及Term的长度。文本经过tokenizer处理后的结果称为token stream。token stream其实就是一个个Token的顺序排列。token stream将等待着filter来处理。

除了tokenizer外,Lucene的另一个重要组成部分就是filter链,filter链将用来处理Token Stream中的每一个token。这些处理方式包括删除Token,改变Token,甚至添加新的Token。Lucene中内置了许多filter,读者也可以轻松地自己实现一个filter。有如下内置的filter:

  • Lowercase filter:把所有token中的字符都变成小写
  • ASCII folding filter:去除tonken中非ASCII码的部分
  • Synonyms filter:根据同义词替换规则替换相应的token
  • Multiple language-stemming
  • filters:把Token(实际上是Token的文本内容)转化成词根或者词干的形式。

所以通过Filter可以让analyzer有几乎无限的处理能力:因为新的需求添加新的Filter就可以了。

1.4 索引和查询

  • 索引过程:Lucene用用户指定好的analyzer解析用户添加的Document。当然Document中不同的Field可以指定不同的analyzer。如果用户的Document中有title和description两个Field,那么这两个Field可以指定不同的analyzer。

  • 搜索过程:用户的输入查询语句将被选定的查询解析器(query parser)所解析,生成多个Query对象。当然用户也可以选择不解析查询语句,使查询语句保留原始的状态。在ElasticSearch中,有的Query对象会被解析(analyzed),有的不会,比如:前缀查询(prefix query)就不会被解析,精确匹配查询(match query)就会被解析。对用户来说,理解这一点至关重要。

对于索引过程和搜索过程的数据解析这一环节,我们需要把握的重点在于:倒排索引中词应该和查询语句中的词正确匹配。如果无法匹配,那么Lucene也不会返回我们喜闻乐见的结果。举个例子:如果在索引阶段对文本进行了转小写(lowercasing)和转变成词根形式(stemming)处理,那么查询语句也必须进行相同的处理。或是查询使用的analyzer必须和索引时使用的analyzer相同。

1.4 查询语言

用户使用Lucene进行查询操作时,输入的查询语句会被分解成一个或者多个Term以及逻辑运算符号。一个Term,在Lucene中可以是一个词,也可以是一个短语(用双引号括引来的多个词)。如果事先设定规则:解析查询语句,那么指定的analyzer就会用来处理查询语句的每个term形成Query对象。

具体的语法细节部分,想要描述起来是个庞大的工程,具体可参考对应文档。

在ES中也可以使用Lucene的语法进行查询,使用方法可参考:https://www.elastic.co/guide/en/elasticsearch/reference/5.2/modules-scripting-expression.html

2. ES 介绍

2.1 介绍

引用我认为最简洁的一句话来概括ES

**Elasticsearch 是一个基于Lucene的分布式搜索和分析引擎.**
  • 1

2.2 基本概念

  • 索引(Index):ElasticSearch把数据存放到一个或者多个索引(indices)中。ElasticSearch内部用Apache Lucene实现索引中数据的读写。但是在ElasticSearch中被视为单独的一个索引(index),在Lucene中可能不止一个。这是因为在分布式体系中,ElasticSearch会用到分片(shards)和备份(replicas)机制将一个索引(index)存储多份。

  • 文档(Document):文档(Document)由一个或者多个字段(Field)组成。ES中的文档(Document)是没有固定的模式和统一的结构。

  • 文档类型(Type):每个文档在ElasticSearch中都必须设定它的类型。文档类型使得同一个索引中在存储结构不同文档时,只需要依据文档类型就可以找到对应的参数映射(Mapping)信息,方便文档的存取。
  • 节点(Node):单独一个ElasticSearch服务器实例称为一个节点。对于许多应用场景来说,部署一个单节点的ElasticSearch服务器就足够了。但是考虑到容错性和数据过载,配置多节点的ElasticSearch集群是明智的选择。

  • 集群(Cluster):集群是多个ElasticSearch节点的集合。是提供高可用与高性能的重要手段

  • 分片索引(Shard):集群能够存储超出单机容量的信息。为了实现这种需求,ElasticSearch把数据分发到多个存储Lucene索引的物理机上。这些Lucene索引称为分片索引,这个分发的过程称为索引分片(Sharding)。

    需要注意的是:集群中分片的数量需要在索引创建前配置好,而且服务器启动后是无法修改的,至少目前无法修改。

  • 索引副本(Replica):当集群负载增长,用户搜索请求可能会阻塞在单个节点上时,通过索引副本(Replica)机制就可以解决这个问题。在提供基础查询性能的同时,也保证了数据的安全性。即如果主分片数据丢失,ElasticSearch通过索引副本使得数据不丢失。索引副本可以随时添加或者删除,所以用户可以在需要的时候动态调整其数量。

  • 网管(Gateway):ES运行过程中需要的所有数据(文档,状态、索引参数等)都被存储在Gateway中。

2.3 工作原理

本部分从启动,故障检测,数据索引,查询 四个部分进行总结

2.3.1 启动

当Elasticsearch节点启动时,会使用发现(discovery)模块来通过发送广播请求的方式发现同一个集群中的其他节点。

在集群中有一个节点被选为主(master)节点。该节点负责集群的状态管理以及在集群拓扑变化时做出反应,分发索引分片至集群的相应节点上去。

在用户看来集群中节点的角色是透明的。使用的过程中不需要知道哪个节点是管理节点,请求可以发送给任意节点,如果有需要,任意节点可以并行发送子查询给其他节点,并合并搜索结果,然后返回给用户。所有这些操作并不需要经过管理节点处理(请记住,Elasticsearch是基于对等架构的)。

在启动阶段,管理节点会读取集群的状态信息并检查有哪些索引分片,并决定哪些分片将用作主分片。此后,整个集群进入黄色状态。
这意味着集群可以执行查询,但是系统的吞吐量以及各种可能的状况是未知的(这种状况可以简单理解为所有的主分片已经被分配了,但是副本没有被分配)。下面的事情就是寻找到冗余的分片用作副本。如果某个主分片的副本数过少,管理节点将决定基于某个主分片创建分片和副本。如果一切顺利,集群将进入绿色状态(这意味着所有主分片以及副本均已分配好)。

2.3.2 故障检测

集群正常工作时,管理节点会监控所有可用节点,通过PING的方式检查它们是否正在工作。如果任何节点在预定义的超时时间内不响应,则认为该节点已经断开,然后错误处理过程开始启动。这意味着可能要在集群–分片之间重新做平衡,选择新的主节点等。对每个丢失的主分片,一个新的主分片将会从原来的主分片的副本中选出来。

2.3.3 与ElasticSearch通信

Elasticsearch对外公开了一个设计精巧的API,通过这些API可以进行索引以及查询的操作,传参的方式主要包括URL携带或是JSON文档的形式。

2.3.4 数据索引

数据索引的方式可以通过简单的API一条一条的索引,也可以通过Bulk API(包括HTTP,UDP两种)进行批量的创建索引。

有一件事情需要记住,建索引操作只会发生在主分片上,而不是副本上。当一个索引请求被发送至一个节点上时,如果该节点没有对应的主分片或者只有副本,那么这个请求会被转发到拥有正确的主分片的节点。然后,该节点将会把索引请求群发给所有副本,等待它们的响应(这一点可以由用户控制),最后,当特定条件具备时(比如说达到规定数目的副本都完成了更新时)结束索引过程。

流程如下
技术图片

2.3.5 查询

Elasticsearch提供了丰富的查询功能,后续章节会对查询功能进行简单的总结,本节主要讨论查询的机制。

关于查询操作需要注意的是:查询并不是一个简单的、单步骤的操作。一般来说,查询分为两个阶段:分散阶段(scatter phase)和合并阶段(gather phase)。在分散阶段将查询分发到包含相关文档的多个分片中去执行查询,而在合并阶段则从众多分片中收集返回结果,然后对它们进行合并、排序,进行后续处理,然后返回给客户端。该机制可以由下图描述。
技术图片

参考

以上是关于ElasticSearch概念与架构原理的主要内容,如果未能解决你的问题,请参考以下文章

Elasticsearch核心原理系列:10张图理解Elasticsearch核心概念

ElasticSearch学习总结:ES介绍与架构说明

elasticsearch扫盲篇

龙叔学ES:elasticsearch扫盲篇

龙叔学ES:elasticsearch扫盲篇

Elasticsearch学习总结--原理篇