实时检索之ElasticSearch

1、概念

ElasticSearch是一个高性能,基于Lucene的全文检索服务,是一个分布式的Restful风格的搜索和数据分析引擎,也可以作为NoSQL数据库使用。Lucene 是apache软件基金会一个开放源代码的全文检索引擎工具包,是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎(搜索引擎和检索程序库不完全等同)。 lucene,最先进、功能最强大的搜索库,直接基于lucene开发,非常复杂,api复杂(实现一些简单的功能,写大量的java代码),需要深入理解原理(各种索引结构)。elasticsearch,基于lucene,隐藏复杂性,提供简单易用的restful api接口、java api接口

 

  • 对Lucene进行了扩展,提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展,并对查询性能进行了优化,还提供了一个完善的功能管理界面。
  • 原型环境和生产环境可无缝切换,无论ElasticSearch是在一个节点上运行,还是在一个包含300节点的集群上运行,都能够以相同的方式与ElasticSearch进行通信。
  • 能够水平扩展,每秒钟可处理海量事件,同时能够自动管理索引和查询在集群中的分布方式,以实现极其流畅的操作。
  • 支持结构化和非结构化数据,支持数字、文本、地理位置、即结构化和非结构化数据。

2、特点

  • 高性能/速度 能立即获得搜索结果。我们通过有限状态转换器实现了用于全文检索的倒排索引,实现了用于存储数值数据和地理位置数据的 BKD 树,以及用于分析的列存储。由于每个数据都被编入了索引,就不必担心某些数据没有索引。
  • 可扩展性 可以在笔记本电脑上运行。也可在承载了 PB 级数据的成百上千台服务器上运行。 原型环境和生产环境可无缝切换;无论是在一个节点上运行,还是在一个包含 300 个节点的集群上运行,您都能够以相同的方式与 Elasticsearch 进行通信。 能够水平扩展,每秒钟可处理海量事件,同时能够自动管理索引和查询在集群中的分布方式,以实现极其流畅的操作。
  • 相关度 搜索所有内容。找到所需的具体信息。基于各项元素(从词频或近因到热门度等)对搜索结果进行排序。将这些内容与功能进行混合和匹配,以对向用户显示结果的方式进行微调。Elasticsearch 功能齐全,可以处理包括各种复杂情况(例如拼写错误)在内的人为错误。
  • 可靠性 /弹性 硬件故障。网络分割。Elasticsearch 为您检测这些故障并确保您的集群(和数据)的安全性和可用性。跨集群复制功能,辅助集群可作为热备份随时投入使用。Elasticsearch 运行在一个分布式的环境中,从设计之初就考虑到了这一点,目的就是让您永远高枕无忧。

3、应用场景

用于日志搜索和分析、时空检索、时序检索、智能搜索等场景。

检索的数据类型复杂:如需要查询的数据有结构化数据、半结构化数据、非结构化数据等,ElasticSearch可以对以上数据类型进行清洗、分词、建立倒排索引等一系列操作,然后提供全文检索的能力。

检索条件多样化:全文检索条件可以包括词或短语。

边写边读:写入的数据可以实时的进行检索。

4、插件扩展层:

  • Logstash:具备实时数据传输能力的管道,着重日志相关处理;负责将数据信息从管道的输入端传输到管道的输出端;支持灵活根据自己的需求在中间加上滤网,Logstash提供里很多功能强大的滤网以满足你的各种应用场景
  • Kibana;开源的分析和可视化平台,数据主要由es提供;基于es的搜索与分析能力,拿到用于上层分析和可视化需要的结果;开发者或运维人员可以轻松地执行高级数据分析,并在各种图表、表格和地图中可视化数据。
  • Beats:专门用于发送数据的平台,可以将数据无缝传输给logstash或是es;轻量级代理机制安装,类似于hadoop集群安装时候的ambari或cdh manager;可将数以百千计算机中的数据发送到logstash或是es中。
  • es-hadoop:一个深度集成Hadoop和es的项目,是es官方维护的一个子项目;可以达到hadoop与es之间的输入与输出;重点是充分利用Map-Reduce的并行计算优势,为hdfs数据提供实时搜索能力。
  • es-sql:用sql来操作es,来代替之前需要写各种复杂的json查询才可解决的问题;es-sql目前有两个版本,第一,是多年前即开始的国内主推开源的nlpchina/es-sql插件,第二,是自2018.06官方es6.3.0发布后正式支持的es-sql功能。
  • elasticsearch-head:将是一款专门针对于elasticsearch的客户端工具,是一个界面化的集群操作和管理工具,可以对集群进行傻瓜式操作,是一个基于node.js的前端工程,
  • Bigdesk:是elasticsearch的一个集群监控工具,可以通过它来查看es集群的各种状态,如:cpu、内存使用情况,索引数据、搜索情况,http连接数等。

5、整体架构

 

 

  • Cluster:代表一个集群,集群中有多个节点,其中有一个为主节点,这个主节点是可以通过选举产生的,主从节点是对于集群内部来说的。
  • EsNode:ElasticSearch节点,一个节点就是一个ElasticSearch实例。
  • EsMaster:主节点,可以临时管理集群级别的一些变更,例如新建或删除索引、增加或移除节点等。主节点不参与文档级别的变更或搜索,在流量增长时,该主节在流量增长时,该主节点不会成为集群的瓶颈。
  • shards:代表索引分片,ElasticSearch可以把一个完整的索引分成多个分片,这样的好处是可以把一个大的索引拆分成多个,分布到不同的节点上。
  • replicas:代表索引副本,ElasticSearch可以设置多个索引的副本,副本的作用一是提高系统的容错性,当某个节点某个分片损坏或丢失时可以从副本中恢复。二是提高Elasticsearch的查询效率,Elasticsearch会自动对搜索请求进行负载均衡。
  • 高性能:虚拟内存设计;磁盘缓存相关参数;swap调优;replica数目;refresh时间间隔;merge相关参数;mapping设置;定期清理cache
  • 多租户:支持多租户;ES实例数根据服务器内存设置,ES单节点实例数 = ES的可用的内存 / 64GB;服务器逻辑磁盘数要跟ES实例数一致,因此ES服务器需要按照实例数做Raid,例如推荐配置256G内存,24块磁盘,那么ES实例数 = 4,需要做4组Raid,每组6块磁盘

核心概念

  • Index:即索引,是ElasticSearch中一个逻辑命名空间,指向一个或多个分片,内部 Apache Lucene实现索引中数据的读写。索引与关系数据库实例Database相当。一个 Elasticsearch 实例可以包含多个索引。
  • Type:文档类型,文档类型使得同一个索引中在存储结构不同的文档时,只需要依据文档类型就可以找到对应的参数映射信息,方便文档的存储。相当于数据库中的Table。一个索引对应一个文档类型。
  • Document :文档,是可以被索引的基本单位,特指最顶层结构或根对象序列化成的 JSON数据。通过相当于数据库中的Row。一个类型包含多 Mapping:映射,用来约束字段的类型,可以根据数据自动创建。相当于数据库中的 Shema。
  • recovery: 代表数据恢复或叫数据重新分布,Elasticsearch在有节点加入或退出时会根据机器的负载对索引分片进行重新分配,挂掉的节点重新启动时也会进行数据恢复。

内部架构

 

 

  • 接口:通过java ,restful api 提供丰富接口,底层基于lucence,通过本地文件,共享文件,hdfs完成索引存储
  • JMX(Java Management Extensions,即Java管理扩展)是一个为应用程序、设备、系统等植入管理功能的框架。JMX可以跨越一系列异构操作系统平台、系统体系结构和网络传输协议,灵活的开发无缝集成的系统、网络和服务管理应用。
  • Lucence Directory:  是lucene的框架服务发现以及选主 ZenDiscovery: 用来实现节点自动发现,还有Master节点选取,假如Master出现故障,其它的这个节点会自动选举,产生一个新的Master
  • Plugins:插件可以通过自定的方式扩展加强Elasticsearch的基本功能,比如可以自定义类型映射,分词器,本地脚本,自动发现等
  • Scripting:使用脚本语言可以计算自定义表达式的值,比如计算自定义查询相关度评分。支持的脚本语言有groovy,js,mvel(1.3.0废弃),python等
  • Disovery:该模块主要负责集群中节点的自动发现和Master节点的选举。节点之间使用p2p的方式进行直接通信,不存在单点故障的问题。Elasticsearch中,Master节点维护集群的全局状态,比如节点加入和离开时进行shard的重新分配
  • River:代表es的一个数据源,也是其它存储方式(如:数据库,官方的river有couchDB的,RabbitMQ的,Twitter的,Wikipedia等)同步数据到es的一个方法。它是以插件方式存在的一个es服务,通过读取river中的数据并把它索引到es中。
  • gateway: 代表Elasticsearch索引快照的存储方式,Elasticsearch默认是先把索引存放到内存中,当内存满了时再持久化到本地硬盘。gateway对索引快照进行存储,当这个Elasticsearch集群关闭再重新启动时就会从gateway中读取索引备份数据。Elasticsearch支持多种类型的gateway,有本地文件系统(默认),分布式文件系统,Hadoop的HDFS和amazon的s3云存储服务。
  • transport: 代表Elasticsearch内部节点或集群与客户端的交互方式,默认内部是使用tcp协议进行交互,同时它支持http协议(json格式)、thrift、servlet、memcached、zeroMQ等的传输协议(通过插件方式集成)。

 6、缓存机制

ElasticSearch缓存主要分三种:Query Cache、Fielddata Cache、Request Cache。

  • Query Cache:属于Node级别的缓存,是对一个查询中包含的过滤器执行结果进行缓存。就是对一个查询中包含的过滤器执行结果进行缓存。常用的term,terms,range过滤器都会在满足某种条件后被缓存。主要用于缓存Filter中的Query结果,基于LRU策略,当缓存满了的情况下,会自动去除一个最近最少被使用的Query Cache。
  • Fielddata Cache:Fielddata是专门针对分词的字段在查询期间的数据结构的缓存。当我们第一次在一个分词的字段上执行聚合、排序或通过脚本访问的时候就会触发该字段Fielddata Cache的加载,这种缓存是“segment”级别的,当有新的segment打开时旧的缓存不会重新加载,而是直接把新的segement对应的Fielddata Cache加载到内存。加载Fielddata Cache是一个非常昂贵的操作,一旦Fielddata被加载到内存,那么在该Fielddata Cache对应的Segement生命周期范围内都会驻留在内存中。也就是说当段合并时会触发合并后更大段的Fielddata Cache加载。Fielddata会消耗大部分的JVM堆内存,特别是当加载“高基数”的分词字段时(那些分词后存在大量不同词的字段),针对这种字段的聚合排序其实是非常没有意义的,我们更多的要去考虑是否能用not_analyzed代替(这样就可以使用doc_values实现聚合、排序)。默认开启的。
  • Request Cache:Shard级别的缓存,是为了缓存“分片级”的本地结果集。目前只会缓存查询中参数size=0的请求,所以就不会缓存hits 而是缓存 hits.total,aggregations和suggestions。Request Cache是非常智能的,它能够保证和在近实时搜索中的非缓存查询结果一致。默认情况下Request Cache是关闭的,需要手动开启。

7、索引流程

    客户端发送批量索引请求至任意节点后,节点将转发请求至对应主分片节点,主分片节点按序操作,完成一个操作后再发送给其余复制节点执行。复制节点操作完成报告给主分片节点,主分片节点报告给请求节点并返回至客户端。

  • 阶段1:客户端向Node 1发送大量(bulkv)请求。
  • 阶段2:Node 1为每个分片构建批量请求,然后转发到这些请求所需的主分片上。
  • 阶段3:主分片一个接一个的按序执行操作。当一个操作执行完,主分片转发新文档(或者删除部分)给对应的复制节点,然后
  • 执行下一个操作。复制节点为报告所有操作完成,节点报告给请求节点,请求节点整理响应并返回给客户端

    传统的搜索方式(正排序索引)是从关键点出发,通过正排序索引进行搜索,就是从通过文档编号找关键词。 ElasticSearch(Lucene)的搜索采用了倒排序索引的方式,而在全文搜索中Value就是我们要搜索的关键词,存放所有关键词的地方叫词典 Key是文档标号列表(通过文档标号列表我们可以找到出现过要搜索关键词--Value的文档),具体如下面的图所示:通过倒排索引进行搜索,就是通过关键词查询对应的文档编号,再通过文档编号找文档,类似于查字典,或通过查书目录查指定页码书的内容。

  • 正排索引:是通过Key寻找Value,即从关键点出发,然后再通过关键点找到信息中满足搜索条件的特定信息。
  • 倒排索引:ElasticSearch所采用得排序方式,是通过Value找Key。而在全文搜索中Value就是要搜索的关键词,通过Value找到对应的文档。

8、搜索流程

节点收到所有待检索的数据后,发送请求给数据相关的分片,收到请求的分片节点会读取数据并返回给检索节点,检索节点汇总结果并返回给客户端。

搜索流程分为两个阶段,即查询阶段与获取阶段。查询阶段主要定位了所要检索数据的具体位置,而获取阶段的任务就是将这些定位好的数据内容取回并返回给客户端

  • 查询阶段: 阶段1:客户端发送一个检索请求给任意节点,假设是Node 3。 阶段2:Node 3将检索请求发送给该index中的每一个shard,此时会采取轮询策略,在primary shard及其所有replica中随机选择一个,让读请求负载均衡。每个shard在本地执行检索,并将结果排序添加到本地。 阶段3:每个shard返回本地所记录的结果,发送给Node 3。Node 3将这些值合并,做全局排序。
  • 获取阶段: 阶段1:Node 3获取了所有待检索数据的定位之后,发送请求给与数据相关的shard。 阶段2:每个收到Node 3请求的shard,将读取相关文档中的内容,并将它们返回给Node 3。 阶段3:当Node 3获取到了所有shard返回的文档后,Node 3将它们合并成一条汇总结果,返回给客户端。

批量搜索流程

客户端发送批量搜索请求至任意节点,该节点为每个分片分别构建一个多条数据检索请求,然后转发至主分片或副本分片。当所有请求执行完成后,请求节点汇总记录并返回给客户端。

阶段1:客户端向Node 1 发送mget 请求。

阶段2:Node 1 为每个分片构建一个多条数据检索请求,然后转发到这些请求所需的主分片或副本分片上。当所有回复被接收,Node 1 构建响应并返回给客户端。

9、性能优化

索引一旦创建好后,就无法调整分片的数量,而ElasticSearch一个分片实际上对应一个存储数据Lucene索引,Lucene索引的读写会占用很多的系统资源,因此,分片副本数需要合理的配置:

  • 分片数不超过节点数的3倍,用较少的分片获得更佳的性能。
  • 副本数建议设置为1,过多的副本需要更多存储空间。
  • 分片最大容量不要超过ElasticSearch推荐的最大JVM堆空间32G。

 

  • Lucene索引,即索引文件格式。结构如下:索引(Index):对应一个文件夹中的;段(Segment):一个索引可以包含多个段,段之间独立,添加新文档可以生成新的段,不同的段可以合并。相同前缀文件的属同一个段。segments.gen和segments_5是段的元数据文件,也即它们保存了段的属性信息。文档(Document):建索引的基本单位,不同的文档是保存在不同的段中的,一个段可以包含多篇文档;域(Field):一篇文档包含不同类型的信息,可以分开索引,比如标题,时间,正文,作者等,都可以保存在不同的域里;词(Term):词是索引的最小单位,是经过词法分析和语言处理后的字符串。
  • 1个Elasticsearch的索引有1个或者多个分片。分片对应实际存储数据的Lucene的索引,分片自身就是一个搜索引擎。Elasticsearch的索引还包含"type"(就像数据库中的表),用于逻辑上隔离索引中的数据。
  • 如果分片数过多,大大超过了节点数,很可能会导致一个节点上存在多个分片,一旦该节点故障,即使保持了1个以上的副本,同样有可能会导致数据丢失,集群无法恢复。
  • Elasticsearch6.X及之前的版本默认索引分片数为5、副本数为1,从Elasticsearch7.0开始调整为默认索引分片数为1、副本数为1
  • 100个分片, 即便很少使用也可能是好的;而2个分片, 即便使用非常频繁, 也可能是多余的。
  • jvm内存建议不要低于2G,否则有可能因为内存不足导致ES无法正常启动或内存溢出,jvm建议不要超过32G,否则jvm会禁用内存对象指针压缩技术,造成内存浪费。32G性能不如40G

 

  • indices.recovery.max_bytes_per_sec:索引恢复每秒最大字节数,默认值为40MB,调整此参数可以使索引恢复的网络带宽增加。
  • cluster.routing.allocation.cluster_concurrent_rebalance:控制集群范围允许多少个并发碎片重新平衡。默认值为2。请注意,此参数仅控制由于群集中的不平衡而导致的并发碎片重定位的数量。

 

posted @ 2021-02-18 18:04  夏日的向日葵  阅读(1001)  评论(0编辑  收藏  举报