前端学习ElasticSearch

205 阅读14分钟

1. ElasticSearch是什么?

Elasticsearch (ES)是开源的近实时分布式搜索分析引擎,内部使用 Lucene 做索引与搜索。它提供"近实时搜索"能力,并且能动态集群规模,弹性扩容,是目前最受欢迎的企业搜索引擎。

ps:Lucene是一套用于全文检索和搜索的开放源码程序库,所以ES也是基于全文检索的

我们提炼一下关键词:

  • 分布式
  • 动态集群、弹性扩容
  • 近实时 (Near) Real Time Search
  • 搜索(Lucene)
  • 分析

1.1 ES的基本概念

在解释这几个关键词之前,我们先了解一下几个ES的基本概念(对照mySql):

MySqlElasticSearch
DatabaseIndex(索引、数据存在1或n个index中)
Table(表)Type(存储的文档类型,比如_doc)
Row(记录/行)Document(文档,Index存放和读取的基本单元)
ColumnField(域,Document由一个或多个Field组成)
SchemeMapping(映射)索引中文档的约束,例如字段类型约束
Index(索引,用于优化)Everything is indexed(任何都能是优化用的index)
Sql(sql语句增删改查)Query Dsl (和任何http请求一样)
Select * from ...Get http://...
Upate table set ...put http://...

关系型数据库 -> Databases(库) -> Tables(表) -> Rows(行) -> Columns(列)。 Elasticsearch -> Indeces(索引) -> Types(类型) -> Documents(文档) -> Fields(属性)。

ES示例:

  • 节点(node):单独一个ES服务器实例称为一个节点。对于许多应用场景来说,部署一个单节点的ES服务器就足够了。但是考虑到容错性和数据过载,通常配置多节点的ES集群
  1. 每个es集群总会自动选出一个节点作为master节点,如果master节点挂了,也会选举出一个新的
  2. master管理es集群的元数据、负责切换主分片和副本分片身份等工作。 比如创建和删除索引,节点的增加和移除
  3. 节点平等:master节点不承载所有请求,每个节点都能接受所有请求
  4. 自动响应路由: 任何一个节点收到请求后,都可以把这个请求自动路由到相关节点上去处理
  5. 响应收集:最原始节点会从其他节点接收响应数据,然后把这些数据返回给客户端
  • 集群(cluster):一个集群通常由1台或多台节点组成,这些节点齐心协力应对单个节点无法处理的搜索需求和数据存储需求,集群同时也是应对由于部分机器(节点)运行中断或者升级导致无法提供服务这一问题的利器。

节点间的合作是不被用户感知的,对外而言就是一个整体,增加或者一个节点,用户不感知,而且配置一个集群也超级简单,这在竞品中有巨大的优势

image.png

  • 索引分片(shard):一个索引可能存储一个巨大数量的数据而远远超出了单机容量

例如你有一个10亿的数据,它的单个索引大小1TB,可能你单个磁盘容不下,或者搜索性能很低下。

为了解决这个问题,es提供了切分大索引为多个分片的能力。

当你创建索引时候,可以配置分片的数量(一旦服务器启动,配置无法更改),每个分片相对于它自己而言都是一份完成的索引,它可以被放在集群中任意的节点上。

多个分片,在写入或查询的时候就可以并行操作(从各个节点中读写数据,提高吞吐量)

  • 索引副本(replica):数据写入的时候是写到主分片,副本分片会复制主分片的数据,读取的时候主分片和副本分片都可以读。
  1. 主分片数据故障或者宕机时(主副分片不在一个节点上),对应的副本可以升级成主分片,保证了数据的不丢失,保证高可用
  2. 副本可以分担搜索请求,提升集群的吞吐量和性能

c. 索引副本可以随时添加或者删除,用户可以在需要的时候动态调整其数量,

image.png 总结一下:

ES集群可由多个节点组成,各分片分布式地存储于这些节点上。每个分片对应一个或者多个分片副本,当分片/节点发生故障时提供高可用性,副本支持扩展搜索量/吞吐量,因为可以在所有副本上并行执行搜索。

ES可自动在节点间按需要移动分片,例如增加节点或节点故障时。简而言之,分片实现了集群的分布式存储,而副本实现了其分布式处理及冗余功能。

ps:如果存在分片和副本,你至少有2台机器在你的集群中(分片和副本不能在一个节点上),否则即使可以使用,也会出现黄色警告,告诉你有未被分配的分片,

基础概念介绍完了,我们来解释一下上面的关键词:

1.2 分布式

分布式系统是一个硬件或软件组件分布在不同的网络计算机上,彼此之间仅仅通过消息传递进行通信和协调的系统

简单来说就是一群计算机集合共同对外提供服务,但是对于系统的用户来说,就像是一台计算机在提供服务一样,分布式意味着更多的计算机组成集群对外服务,计算机越多,cpu、内存、存储资源等也越多,能够处理并发访问量也就越大

没错,这里就是指得ES的集群概念

1.3 动态集群、弹性扩容

这里主要指的是ES轻松的横向拓容,可支持PB级的结构化或非结构化数据处理

横向扩容:当存储容量不够的时候,可以通过增加节点来解决存储问题,也就是增加机器, GB->TB->PB

什么是横向扩容?

举个栗子:

6台服务器,每台容纳1T的数据,马上数据量要增长到8T,这个时候有两个方案。

  1. 垂直扩容:重新购置两台服务器,每台服务器的容量就是2T,替换掉老的两台服务器,那么现在6台服务器的总容量就是 4 * 1T + 2 * 2T = 8T。
  2. 横向扩容:新购置两台服务器,每台服务器的容量就是1T,直接加入到集群中去,那么现在服务器的总容量就是8 * 1T = 8T

垂直扩容:采购更强大的服务器 ,成本非常高昂,而且会有瓶颈,假设世界上最强大的服务器容量就是10T,但是当你的总数量达到5000T的时候,那么你要采购多少台最强大的服务器。

水平扩容:业界经常采用的方案,采购越来越多的普通服务器,性能比较一般,但是很多普通服务器组织在一起,就能构成强大的计算和存储能力。

ES的横向扩容机制是什么?

场景:1个index包含3T的数据,每个节点可以承载1T的数据,设置的分片有3个,每个分片都是一个最小工作单元,承载部分数据,是一个lucene实例,可以完整的建立索引和处理请求能力

增删节点时,分片会自动在节点中负载均衡,比如新增一个节点(一台机器),每个节点有更少的分片, 意味着每个分片可以占用更多的资源,IO\cpu\memory,整个系统性能会更好。

1.4 近实时 (Near) Real Time Search

实时搜索(Real-time Search)很好理解,对于一个数据库系统,执行插入以后立刻就能搜索到刚刚插入到数据。而近实时(Near Real-time),所谓“近”也就是说比实时要慢一点点。

ES的近实时是什么样的?

要想解释清楚ES的近实时,首先了解一下ES的写入策略:

上面我们已经知道,ES写入数据是写到主分片上的

  1. 集群中每个节点都是协调节点,协调节点都可以充当路由,客户端写入的时候,请求到了节点1,但是发现这个请求的数据应该由节点2(主分片在这)处理,会转发到节点2上
  2. 请求到达对应节点2和对应的主分片,开始工作了:
  • 将数据写到内存缓存区(in-memory buffer)
  • 然后将数据写到translog缓存区
  • 每隔1s(可以配置)数据从buffer中refresh到文件系统缓存(FileSystemCache)中,生成segment文件,一旦生成segment文件,就能通过索引查询到了
  • refresh完,memory buffer就清空了。
  • 每隔5s中,translog 从buffer flush到磁盘中
  • 定期/定量(文件大到一定程度或者超过了30分钟)从FileSystemCache中,结合translog内容异步flush index到磁盘中, 完成持久化操作。
  1. 等主分片写完了以后,会将数据并行发送到对应的存副本的节点上,等到所有的节点写入成功就返回ack给协调节点,协调节点返回ack给客户端,完成一次的写入。

近实时:Elasticsearch会把数据先写入内存缓冲区,然后每隔1s刷新到文件系统缓存区,这时候数据才可以被检索到。Elasticsearch写入的数据需要1s才能查询到,所以它是近实时的

in-memory buffer的作用是实现批量变更到文件系统缓存。 文件系统缓存的引入是为了解决随机IO(fsync)的高昂代价,如果每次索引一个文档都会执行一次随机IO的话会造成很大的性能问题

ps:为了防止节点宕机,内存中的数据丢失,Elasticsearch会另写一份数据到日志文件上,但最开始的还是写到内存缓冲区,每隔5s才会将缓冲区的刷到磁盘中。所以:Elasticsearch某个节点如果挂了,可能会造成有5s的数据丢失。

1.5 搜索

传统的数据库,首先是存储,搜索只是顺便提供的功能。

比如MySqL, 它架构天生不适合海量数据查询,它只适合海量数据存储,但无法应对海量数据下各种复杂条件的查询,它是搜索采用的是B+树索引,来实现快速检索,但是

  • 加索引确实可以提升查询速度,但在 MySQL 中加多个索引最终在执行 SQL 的时候它只会选择成本最低的那个索引,如果最低成本的索引不满足 就会触发全表扫描,即使有组合索引,也要符合最左前缀原则才能命中,海量数据查询下,组合索引非常容易索引搜索失效
  • 存储是需要成本的,每加一个索引,就会创建一颗 B+ 树,海量数据下,将会增加很大的存储成本,比如出现某个表只有10G,索引却有30G的情况
  • 有些查询,加索引解决不了问题,比如模糊查询,想搜Elasticsearch,我输入Elastics,你用sql 肯定查不出来

综上所述,MySQL 的查询确实能力有限。

针对海量数据查询的这些问题,ES都能做,而且还很擅长。

ElasticSearch 中文翻译 “弹性搜索”,顾名思义 就是专攻搜索的搜索引擎,不把数据存下来就搜不了,所以只好存一存,所以它也支持存储,配置存储的策略是为了更好的支持搜索

它有三个特点:

  • 轻松支持各种复杂的查询条件:它是分布式实时文件存储,会把每一个字段都编入索引(倒排索引),利用高效的倒排索引,以及自定义打分、排序能力与丰富的分词插件等,能实现任意复杂查询条件下的全文检索需求。

  • 可扩展性强:支持分布式存储,通过极其简单的配置实现几百上千台服务器的分布式横向扩容,轻松处理 PB 级别的结构化或非结构化数据。

  • 高可用,容灾性能好:通过使用主备节点,以及故障的自动探测与恢复,有力地保障了高可用。

那么 ES 中的索引为何如此高效,能在海量数据下达到秒级的效果呢?

我们之前提到过,ES是基于Lucene,采用的是全文检索,那么‘全文’是啥意思?

关系型数据库(比如mySql),把原本非常形象的对象,拍平了,拍成各个字段,存在数据库,查询时,再重新构造出对象;ES则是文档存储,把对象原原本本地放进去,取出时直接取出。

  • 倒排索引

它采用了多种优化手段,最主要的原因是它采用了一种叫做倒排索引的方式来生成索引,避免了全文档扫描。对于文档搜索来说,倒排索引在性能和空间上都有更加明显的优势。

场景:假设有以下三个文档(Document):

我们要在其中找到含有 comming 的文档,如果要正排索引,那么要把每个文档的内容拿出来查找是否有此单词,毫无疑问这样的话会导致全表扫描,那么用倒排索引会怎么查找呢?

它首先会将每个文档内容进行分词,小写化等,然后建立每个分词与包含有此分词的文档之前的映射关系。

如果有多个文档包含此分词,那么就会按重要程度即文档的权重(通常是用 TF-IDF 给文档打分)将文档进行排序。

于是我们可以得到如下关系:

这样的话我们我要查找所有带有 comming 的文档,就只需查一次,而且这种情况下查询多个单词性能也是很好的,只要查询多个条件对应的文档列表,再取交集即可,极大地提升了查询效率。

分词策略、打分策略、根据单词表定位单词这些,大家感兴趣可以去查一下,这里略过了...

  • 联合索引查询

场景:我们需要查询评分高于4.5分的科幻电影

我们只需要分别对分数、分类字段倒排索引查询,获取到文档列表,再做交集合并即可,

mySql是不支持合并操作的,只能按照一个字段的索引进行查询,然后根据另一字段的条件做内存过滤。

ES支持多种方式(跳表 Skip List、Bitset )的方式将数据集进行合并。

1.6 分析

和 mysql 一样,ES 提供了一些简单的聚合操作,平均值、总数、最大值等等。

但是在实际的业务场景中,很多是无法通过这些聚合操作分析出想要的数据,复杂的处理逻辑还是要通过业务代码代码实现

比如前端监控中的日志,是在kafka消费后,把聚合数据处理好,才存到es中的

我理解的是它的分析指两方面

  • 处理搜索时进行模糊查询的分析你的意图
  • 生态上,有一个专攻分析es数据的工具Kibana,它和ES同属于一家公司,是一个开源分析可视化平台,旨在与Elasticsearch协同工作,可以使用Kibana搜索、查看和与存储在 ES 索引中的数据进行交互。

2. ES能替代MySQL吗?

两个产品不同,无法替代

MySQL 不适用于检索,但支持事务类型,可以保证不会出现脏数据,ES 不支持事务,不是很适合存储原始数据;

如果有事务要求,比如商品的下单支付等业务操作,无疑使用MySQL。如果是海量数据的搜索,分析和计算,无疑可以使用Elasticsearch。

两者是一个互补而不是替代的关系。

3. 总结

3.1 ES能做的事情:

3.2 适合的场景:

3.3 一线公司使用现状

  • 维基百科、github - 站内实时搜索
  • 携程- 酒店订单、机票
  • 京东- 到家订单中心
  • 各种监控系统arms
  • 等等