详解最热门搜索引擎ES
详解最热门搜索引擎——ES
一、产生背景
互联网发展早期的时候,对于一般的公司储存的数据量不是那么的大,所以很多公司更倾向于使用数据库去存储和查询数据,如:现在去MySQL中查询数据,大概的查询方式就是:select * from table where filed like “%XXX%”或者其他方式,但是,如果我们在查询的时候没有用到或命中数据库建立的索引话,则会扫描整张表,即便是MySQL做过单表查询能力优化,但是他的极限也只在400万左右,且还会经常出现超时现象,让后为了解决这些问题,。很多公司就开始对数据库进行拆分(水平拆分和垂直拆分),这样虽然是解决查询效率的问题,但是也引入了新的问题:1、垂直拆分的话会出现数据库单点故障,先天的主从复制关系,增加了公司的运维成本;2、对表进行拆分的话,增加维护难度和增加公司运维成本;3、即使做了大量的维护,但在大数据的条件下对于数据的检索还是达不到期望的值。随着在业务的不断扩展,数据量的不断膨胀,显然,传统的查询方式已然不能够满足用户的需求,因此就出现了ES这个强大的分布式的,基于RESTful风格的全文搜索引擎。
1、传统方式:
2、Es方式:
二、应用场景
1、作为数据库(代替MySQL);
- 前提:没有频繁更新(一秒内有大量的更改操作),不需要事务处理,需要对数据进行检索,统计;
- 优点:容错性好;单点故障时,可以通过复制数据到不同的服务器上达到容错的目的;
2、在大数据条件下做检索服务、同义词处理、相关度排名、复杂数据分析、海量数据的近实时处理;
3、记录和日志的分析
* 可以使用ELK对海量的数据进行近实时的处理,对复杂的日志进行收集分析
4、全文检索
5、关系型数据库的补充,传统数据库的替代
6、站内搜索、垂直搜索
很多电商网站可以说是站内搜索
垂直搜索:是针对某一行业的专业搜索引擎,是搜索的细分和延伸,对网页库中的某类专门的信息做一次整合,定向分字段抽取出
要的数据进行处理后再以某种形式返回给用户。
相较于通用搜索引擎的信息量大,查询不准确,深度不够,垂直搜索作为新的搜索引擎服务模式,通过针对某一特定领域,某一特人群或者是某一特定需求,提供的有一定价值的信息和相关服务,更加专注、具体和深入,且具有一定的行业色彩。
通俗意义上,垂直搜索引擎是网站、APP 里面提供的搜索窗口,让用户通过搜索关键词就能直达目标内容。
例如:
1、淘宝、天猫、京东是电商商品领域的垂直搜索引擎。
2、知乎是知识问答领域的垂直搜索引擎。
3、谷歌、百度、必应则是面向通用领域、索引海量信息、试图服务全网用户的通用搜索引擎。
三、基础架构/核心流程
1、基本概念:
elasticsearch设计的理念就是分布式搜索引擎,底层实现是基于Lucene的,核心思想是在多态机器上启动多个es进程实例,组成一个es集群。
接近实时
es是一个接近实时的搜索平台,这就意味着,从索引一个文档直到文档能够被搜索到有一个轻微的延迟
集群 (cluster)
一个集群有多个节点(服务器)组成,通过所有的节点一起保存你的全部数据并且通过联合索引和搜索功能的节点的集合,每一个集群有一个唯一的名称标识
节点 (node)
一个节点就是一个单一的服务器,是你的集群的一部分,存储数据,并且参与集群和搜索功能,一个节点可以通过配置特定的名称来加入特定的集群,在一个集群中,你想启动多少个节点就可以启动多少个节点。
索引 (index)
一个索引就是还有某些共有特性的文档的集合,一个索引被一个名称唯一标识,并且这个名称被用于索引通过文档去执行搜索,更新和删除操作。
类型 (type)
type 在6.0.0已经不赞成使用
文档 (document)
一个文档是一个基本的搜索单元
总结 :
ES中,存储数据的基本单位就是索引,比如说ES中存储了一些订单系统的销售数据,就因该在ES中创建一个索引(order—index),所有的销售数据就会都写到这个索引里面去,一个索引就像一个数据库,而type就相当于每一张表。一个index里面可以有多个type,而mapping就相当于表的结构定义,定义了什么字段类型等,你往index的一个type里添加一行数据就叫做一个document,每一个document有多个filed,每一个filed就代表这个document的一个字段的值。
分片 (shards)
在一个搜索里存储的数据,潜在的情况下可能会超过单个节点的硬件的存储限制,为了解决这个问题,elasticsearch便提供了分片的功能,它可以将索引划分为多个分片,当你创建一个索引的时候,你就可以简单的定义你想要的分片的数量,每一个分片本身是一个全功能的完全独立的索引,可以部署到集群中的任何一个节点。分片的两个总要原因:
(1)它允许你水平切分你的内容卷
(2)它允许通过分片来分布和并执行操作来应对日益增长的执行量
复制 (replica)
在一个网络情况下,故障可能会随时发生,有一个故障恢复机制是必须的,为了达到这个目的,ES允许你制作一个或多个拷贝放入一个叫做复制分片或短暂的复制品中。复制对于以下两个主要原因很重要
(1)高可用。它提供了高可用的以来防止分片或者节点宕机,为此,一个非常重要的注意点就是绝对不要将一个分片的拷贝放在跟这个分片相同的机器上。
(2)高并发。它允许你的分片可以提供超出自身吞吐量的搜索服务,搜索行为可以在分片所有的拷贝中并行执行。
2、ES的核心流程:
(1) ES的写数据的过程 :
ES客户端将一份数据写入primary shard,它会将分成成对的shard分片,并将数据进行复制;Elasticsearch采用多Shard方式,通过配置routing规则将数据分成多个数据子集,每个数据子集提供独立的索引和搜索功能。当写入文档的时候,根据routing规则,将文档发送给特定Shard中建立索引。以这样的方式来实现分布式系统;
每个Index由多个Shard组成,每个Shard有一个主节点和多个副本节点,副本个数可配。但每次写入的时候,写入请求会先根据_routing规则选择发给哪个Shard,Index Request中可以设置使用哪个Filed的值作为路由参数,如果没有设置,则使用Mapping中的配置,如果mapping中也没有配置,则使用_id作为路由参数,然后通过_routing的Hash值选择出Shard(在OperationRouting类中),最后从集群的Meta中找出出该Shard的Primary节点。
请求接着会发送给Primary Shard,在Primary Shard上执行成功后,再从Primary Shard上将请求同时发送给多个Replica Shard,请求在多个Replica Shard上执行成功并返回给Primary Shard后,写入请求执行成功,返回结果给客户端。
这种模式下,写入操作的延时就等于latency = Latency(Primary Write) + Max(Replicas Write)。只要有副本在,写入延时最小也是两次单Shard的写入时延总和,写入效率会较低,但是这样的好处也很明显,避免写入后,单机或磁盘故障导致数据丢失,在数据重要性和性能方面,一般都是优先选择数据,除非一些允许丢数据的特殊场景。
单独的每一个节点中的操作:
在每一个Shard分片中,写入流程分为两部分,先写入Lucene,再写入TransLog。写入请求到达Shard后,先写Lucene文件,创建好索引,此时索引还在内存里面,接着去写TransLog,写完TransLog后,刷新TransLog数据到磁盘上,写磁盘成功后,请求返回给用户。这里有几个关键点:
一是和数据库不同,数据库是先写CommitLog,然后再写内存,而Elasticsearch是先写内存,最后才写TransLog,一种可能的原因是Lucene的内存写入会有很复杂的逻辑,很容易失败,比如分词,字段长度超过限制等,比较重,为了避免TransLog中有大量无效记录,减少recover的复杂度和提高速度,所以就把写Lucene放在了最前面。
二是写Lucene内存后,并不是可被搜索的,需要通过Refresh把内存的对象转成完整的Segment后,然后再次reopen后才能被搜索,一般这个时间设置为1秒钟,导致写入Elasticsearch的文档,最快要1秒钟才可被从搜索到,所以Elasticsearch在搜索方面是NRT(Near Real Time)近实时的系统。
三是当Elasticsearch作为NoSQL数据库时,查询方式是GetById,这种查询可以直接从TransLog中查询,这时候就成了RT(Real Time)实时系统。四是每隔一段比较长的时间,比如30分钟后,Lucene会把内存中生成的新Segment刷新到磁盘上,刷新后索引文件已经持久化了,历史的TransLog就没用了,会清空掉旧的TransLog。
扩展: 增加transLog的原因:当机器宕机或者挂掉,保证内存中的数据不会丢失
原因:采用多个副本后,避免了单机或磁盘故障发生时,对已经持久化后的数据造成损害,但是Elasticsearch里为了减少磁盘IO保证读写性能,一般是每隔一段时间(比如5分钟)才会把Lucene的Segment写入磁盘持久化,对于写入内存,但还未Flush到磁盘的Lucene数据,如果发生机器宕机或者掉电,那么内存中的数据也会丢失,这时候如何保证?
(2)ES的读数据的过程
查询,GET某一条的数据,写入某个document,这个document会自动给你分配一个全局的唯一ID,同时跟住这个ID进行hash路由到对应的primary shard上面去,当然也可以手动的设置ID
- 客户端发送任何一个请求到任意一个node,成为coordinate node
- coordinate node 对document进行路由,将请求转发到对应的node,此时会使用round-robin随机轮训算法,在primary shard 以及所有的replica中随机选择一个,让读请求负载均衡,
- 接受请求的node,返回document给coordinate note
- coordinate node返回给客户端
(3)ES的搜索数据过程
- 客户端发送一个请求给coordinate node
- 协调节点将搜索的请求转发给所有的shard对应的primary shard 或replica shard
- query phase:每一个shard 将自己搜索的结果(其实也就是一些唯一标识),返回给协调节点,有协调节点进行数据的合并,排序,分页等操作,产出最后的结果
- fetch phase ,接着由协调节点,根据唯一标识去各个节点进行拉去数据,最总返回给客户端
- 底层原理:
查询过程大体上分为查询和取回这两个阶段,广播查询请求到所有相关分片,并将它们的响应整合成全局排序后的结果集合,这个结果集合会返回给客户端。
- 查询阶段
- 当一个节点接收到一个搜索请求,这这个节点就会变成协调节点,第一步就是将广播请求到搜索的每一个节点的分片拷贝,查询请求可以被某一个主分片或某一个副分片处理,协调节点将在之后的请求中轮训所有的分片拷贝来分摊负载。
- 每一个分片将会在本地构建一个优先级队列,如果客户端要求返回结果排序中从from 名开始的数量为size的结果集,每一个节点都会产生一个from+size大小的结果集,因此优先级队列的大小也就是from+size,分片仅仅是返回一个轻量级的结果给协调节点,包括结果级中的每一个文档的ID和进行排序所需要的信息。
- 协调节点将会将所有的结果进行汇总,并进行全局排序,最总得到排序结果。
- 取值阶段
- 查询过程得到的排序结果,标记处哪些文档是符合要求的,此时仍然需要获取这些文档返回给客户端
- 协调节点会确定实际需要的返回的文档,并向含有该文档的分片发送get请求,分片获取的文档返回给协调节点,协调节点将结果返回给客户端。
2、分片设计与管理
ES 中的文档存储在索引中,索引的最小存储单位是分片,不同的索引存储在不同的分片中。
当讨论分片时,一般是 基于某个索引 的,不同索引之间的分片互不干扰。
分片分为 主分片 和 副本分片 两种;副本分片是主分片的拷贝,主要用于备份数据。
关于 :
- 主分片数:主分片数在索引创建时确定,之后不能修改。
- 在 ES 7.0 以后,一个索引 默认 有一个主分片。
- 一个索引的主分片数不能超过 1024 。
- 副本分片数:副本分片数在索引创建之后可以动态修改。
- 副本分片数默认为 1。
关于每个节点上的分片数的设置,可参考 。
(1)主分片的设计
如果某个索引只有 一个主分片 :
优点:查询算分和聚合不精准的问题都可避免。
缺点:集群无法实现水平扩展。
a、因为索引(不管该索引的数据量达到了多大)只能存储在一个主分片上(一个分片不能跨节点存储/处理);
b、对于单个主分片的索引来说,即使有再多的数据节点,它也无法利用。
如果某个索引有 多个主分片 :
优点:集群可以实现水平扩展。
a、对于拥有多个主分片的索引,该索引的数据可以分布在多个主分片上,不同的主分片可以分布在不同的数据节点中;这样,该索引就可以利用多个节点的读写能力,从而处理更多的数据。
b、如果当前的 数据节点数 小于 主分片数 ,当有新的数据节点加入集群后,这些主分片就会自动被分配到新的数据节点上,从而实现水平扩容。
缺点:但是主分片数也不能过多,因为对于分片的管理也需要额外的资源开销。主要会带来以下问题:
a、每次搜索/聚合数据时需要从多个分片上获取数据,并汇总;除了会带来精准度问题,还会有性能问题。
b、分片的 Meta 信息由 Master 节点维护管理,过多的分片,会增加 Master 节点的负担。
对于 分片的设计建议 :
从分片的存储量考虑:
a、对于日志类应用,单个分片不要大于 50G;
b、对于搜索类应用,单个分片不要大于 20G;
从分片数量考虑:
a、一个 ES 集群的分片**(包括主分片和副本分片)**总数不超过 10 W。
(2)副本分片的设计
副本分片是主分片的备份:
- 优点:
- 可防止数据丢失,提高系统的可用性;
- 可以分担主分片的查询压力,提高系统的 查询 性能。
- 缺点:
- 与主分片一样,需要占用系统资源,有多少个副本,就会增加多少倍的存储消耗。
- 会降低系统的写入速度。
3、基本架构:
- ES是一个具有搜索引擎,NOSQL数据库功能,RESTful风格,基于Java Lucene架构构建,可用作全文搜索,结构化搜索,近实时分析的开源系统;
- ES是面向文档性的数据库,存储的是整个文档或者对象,不但会存储他们,还会为他们建立索引,提供搜搜功能;
4、怎样提升检索效率:
filesystem cache
ES的搜索引擎是严重的依赖底层的filesystem cache,如果给filesystem cache更多的内存,尽量让内存可以容纳所有的index segment file 索引数据文件
数据预热
对于那些你觉得比较热的数据,经常会有人访问的数据,最好做一个专门的缓存预热子系统,就是对热数据,每隔一段时间,你就提前访问以下,让数据进入filesystem cache里面去,这样期待下次访问的时候,性能会更好一些。
冷热分离
5、性能优化:
关于ES的性能优化,数据拆分,将大量的搜索不到的字段,拆分到别的存储中去,这个类似于MySQL的分库分表的垂直才分。
- document的模型设计
不要在搜索的时候去执行各种复杂的操作,尽量在document模型设计的时候,写入的时候就完成了,另外对于一些复杂的操作,尽量要避免
- 分页性能优化
翻页的时候,翻得越深,每个shard返回的数据越多,而且协调节点处理的时间越长,当然是用scroll,scroll会一次性的生成所有数据的一个快照,然后每次翻页都是通过移动游标完成的。 api 只是在一页一页的往后翻
四、竞品对比
1、solr简述:
- 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有一个插件架构,以支持更多的高级定制。
2、Elasticsearch 与 Solr 的比较
安装管理 | 管理 | 支持的文件格式及其API设计 | 功能 | 搜索表现 | 效率 | 社区 | |
---|---|---|---|---|---|---|---|
ES | 基本上是开箱即用,安装简易 | 自身带有分布式协调管理功能 | 进支持JSON格式; 基于web service 的API | ES本身更注重核心的功能,其他高级功能有第三方插件提供 | 处理大数据,实时搜索应用是效率很高,秒级,适用于新型的实时搜索应用 | ES建立索引快(查询快,插入、更新慢),即实时性的查询快,用于百度,Google,Facebook,新浪等搜索应用 | 相对开发者较少,更新技术较快,学习使用的成本较高 |
Solr | 稍微复杂一点,也很简单 | 利用Zookeeper进行分布式管理 | 支持很多种格式,XML,JSON,CSV; 基于RESTful风格的API | 提供的功能较多,更完善 | 适用于传统的搜索应用 | Solr查询慢,更新索引慢(插入,删除索引快),适用于电商等领域的搜索 | 比较成熟,有一个更大,更成熟,开发和贡献者的社区 |
五、性能分析
1、对已有数据检索:
单纯的对已有的数据进行检索时,solr较好
2、当实时建立索引时:
solr会产生I/O阻塞,查询效率比较差,ES更具优势
3、大数据的条件下检索:
六、应用实践
项目:ES-jd(仿京东搜索)
地址:
七、部署运维
1、安装
下载安装,开箱即用
方法一:
下载地址:https://www.elastic.co/cn/downloads/elasticsearch
方法二:使用命令(mac为例)
1、安装:
brew install elasticserach
2、产看版本(检验安装是否成功)
elasticsearch –version
3、启动
sh ./bin/elasticsearch
其他命令可在bin目录下面看,见下图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rjuGaVHo-1628491470012)(/Users/zhengchao/Library/Application Support/typora-user-images/image-20210730155101685.png)]
4、检验启动是否成功
浏览器访问:http://localhost:9200,出现以下的界面表示成功
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xv2jd2oe-1628491470013)(/Users/zhengchao/Library/Application Support/typora-user-images/image-20210730155539086.png)]
5、关闭es
方法一:使用插件 elasticsearch——head插件(见扩展)
方法二:使用 kill 命令杀死进程
### 2、部署运维
配置:
(1)、ES 有以下不同类型的节点:
Master
(eligible)节点:只有 Master eligible 节点可以成为 Master 节点。
Master 节点用于维护索引信息和集群状态。
Data 节点:负责数据存储。
Ingest 节点:数据预处理。
Coordinating 节点:处理用户请求。
ML 节点:机器学习相关功能。
在开发环境中,一个节点可以承担多种角色。但是在生产环境,建议一个节点只负责单一角色,以达到高可用性及高性能。同时根据业务需求和硬件资源来合理分配节点。
(2)、节点配置参数
在默认情况下,一个节点会同时扮演 Master eligible Node,Data Node 和 Ingest Node。
各类型的节点配置参数如下:
节点类型 配置参数 默认值 Master eligible node.master true Data Node node.data true Ingest Node node.ingest true Coordinating 无 - ML node.ml true(需要 enable x-pack) 默认情况下,每个节点都是一个 Coordinating 节点,可以将
node.master
,node.data
和node.ingest
同时设置为false
,让一个节点 只负责 Coordinating 节点的角色。(3)、配置单一角色
默认情况下,一个节点会承担多个角色,可以通过配置让一个节点只负责单一角色。
单一职责节点配置:
Master节点:从高可用和避免脑裂的角度考虑,生产环境可配置 3 个 Master节点。
node.master:
true
node.ingest:
false
node.data:
false
Data 节点
node.master:
false
node.ingest:
false
node.data:
true
Ingest节点
node.master:
false
node.ingest:
true
node.data:
false
Coordinating节点
node.master:
false
node.ingest:
false
node.data:
false
集群架构:
(1)、水平扩展:
a、当需要更多的磁盘容量和读写能力的时候,可以增加Date Node的节点数量;
b、当系统有大量的复杂查询和聚合分析时,可以增加 Coordinating Node 协调节点的数量;
(2)、读写分离:
a、使用Ingest节点对数据预处理;
集群的监控检查:
(1)、集群状态为 Green 只能代表分片正常分配,不能代表没有其它问题。
ES 提供了很多监控相关的 API:
- [_cluster/health]:集群健康状态。
- [_cluster/state]:集群状态。
- [_cluster/stats]:集群指标统计。
- [_cluster/pending_tasks]:集群中正在执行的任务。
- [_tasks]:集群任务。
- [_cluster/allocation/explain]:查看集群分片的分配情况,用于查找原因。
- [_nodes/stats]:节点指标统计。
- [_nodes/info]:节点信息。
- [_index/stats]:索引指标统计。
- 一些 [cat]API。
(2)Slow log
ES 的 [Slow log]可以设置一些阈值,当写入时间或者查询时间超过这些阈值后,会将相关操作记录日志。
(3)监控工具:
Elasticsearch-support-diagnostics 工具:支持elasticsearch和logstash的诊断实用程序 支持诊断实用程序支持诊断实用程序是一个Java可执行文件,它将查询运行在主机上的node,以获取正在运行的群集的数据和统计信息