stone

elasticsearch-基础篇
做了好几天的elasticsearch集群的搭建和调优,现在做一个小总结,这个可能会写好几篇文章,内容比较多,慢慢...
扫描右侧二维码阅读全文
22
2017/03

elasticsearch-基础篇

做了好几天的elasticsearch集群的搭建和调优,现在做一个小总结,这个可能会写好几篇文章,内容比较多,慢慢来吧。
在进行调优的时候,最大的感受就是调优必须要有方法论,做事的方法论很重要,否则就是在浪费时间。不说了,这都是泪T^T。

elasticsearch介绍

elasticsearch是一种分布式可扩展的近实时搜素引擎,其底层是基于Lucene的,也可以这么理解,每一个节点都是一套独立的Lucene搜索引擎。与其说是一个搜索引擎,更贴切的说法应该是一个非关系型数据库,
可以使用elasticsearch 储存和处理PB级别的结构化,非结构化数据。

elaticseasrch 集群有一个很大的特点就是每一个节点的地位都是平等的,都可以独立成为一个系统,是一种无中心的集群模式,这样的组群方式让它的部署,横向扩展非常灵活,只要起来一台es节点,通过自动发现机制,就可以自动加入已有的集群中。
因为其底层是基于Lucene的,所以很多的概念都是相似的,在了解elasticsearch之前要先了解一些信息检索系统的基础知识:

信息检索系统原理

索引过程包括了创建索引,删除索引等等操作。那这里要先讲解一下倒排索引和正排索引的概念:

在我们平时看到的文件系统实际上是一种正排索引,通过文档的ID(文件名等等)找到文件的内容(文档中的词),在这样的索引中,如果要寻找某一个词在那些文档中,则需要一个文档一个文档读入内存,扫描一次,这样的操作的效率是有多低。和正排索引相反,倒排索引是记录文件内容(文档中的词)出现在那些文档中,形式比较像这样:

有了这样的一个倒排表之后,我们就可以进行检索了,假如我要搜索含有word1的文档,但是不能含有word2,这时Lucene会对查询请求进行预处理,分词等等操作,然后等到这些词之间的一个逻辑关系,然后分别去找到含有word1和word2的文档列表,然后用word1的列表减去word2的列表,这样就可以得到查询结果。很容易看去,这种倒排索引的效率是极高。但是这种查询效率的提升也带来了较长的建立索引和一定的储存空间。

那么倒序索引又是怎么建立的呢?

  1. 当一段文档输入到Lucene中,会经过一系列的Analyzer,进行分词,去掉停用词,词形变换,相近词变换等等操作
  2. 然后将需要建立索引的Field建立索引,并将需要储存的Field进行储存
  3. 将索引写入储存器中

在实际中,建立索引的使用的Analyzer,也要对查询的词做一样的处理,这样才能命中,当然也可以使用不同的Analyzer。

下面是一些Lucene中的常见术语:

  • index: 索引,一个Lucene索引会保存在一个文件夹中
  • document:文档,索引的基本单位,可以是一篇文章,一条话单等等,当段的数量比价多的时候,会进行段合并操作
  • segment:段,一个段包含多个文档,存储为一个文件
  • term:词,索引的最小单位,一般为经过处理的词
  • token:词的一次出现为一个token,有两部分组成,文档id和响应的偏移量

elasticsearch基础

下面正式来看一下ES的结构,ES是一种无中心的结构模式,ES有自己的一套服务发现机制,当一个ES节点启动之后,会自动去寻找已经存在的ES集群,然后加入其中,这给集群的扩展带来的极大的便利。

在ES中,索引是分布式的,由多个的shard和多个replica组成,每一个shard可以看作一个独立的Lucene系统,即shard是一个完成的Lucene索引结构。如下图,这是一个三个节点的ES集群,共有3个shard,每个replica又有1个副本,共6个shard。

一般ES会提供两个端口,分别是9200的http端口和9300的rpc端口,9200用于restful请求,9300用于集群中不同节点之间的通讯。一般的程序都是通过9200端口操作es集群。

在ES集群中,节点可以扮演3中不同的角色,master node,data node和ingest node。ingest node是5.x之后加入的。通过配置node.master,node.data,node.ingest进行配置。master节点中主要储存集群中元信息,如分片位置,索引信息等等,master的作用跟单个jvm中的同步关键字synchronized相同,集群中多节点协调工作必须要保证数据的一致性,但是不同节点分布在不同的jvm中,不可能用jvm的同步机制。所以需要一个“锁”,节点操作集群中的资源时都通过它来解决一致性问题。data节点储存索引数据,ingest节点目前不太清楚,后面专门总结一下这部分,听说可以极大地提升集群性能。

在elasticsearch上主要有几种操作,分别是index,search,启动,恢复。下面分别看看这两个过程的:

Indexing

当一个index请求通过9200发送给ES集群之后,会想先去计算这个索引应该存放的位置,默认是采用hash来进行计算(文档Id mod shard数量),所以在指定index结构之后,是不能改变shard的数量的,如果改变了,这个映射关系就会出错,但是我们可以采用reindex的方法重新建立索引来改变原来的结构,当然这是一个代价很高的操作。在计算出索引所在位置之后,会通过9300接口转发到对应的节点之上。

当节点接收到需要建立索引的数据时,会先将其放在内存中,这个内存会在指定时间之后写入文件,默认为1s,或者在内存满了之后,写入文件之后就是生成一个段文件。这个段文件是不会被修改的,这样的过程叫做flush。当一个索引数据写入文件之后,才能被检索到,所以并不是当索引插入之后就能被直接检索得到,这就是ES的近实时搜索的特性。

删除索引其实也是一个index的过程,删除不是直接删除索引,其实就是在索引上打上delete标签,然后和其他index操作一样,写入段文件中,然后在进行段合并的时候,才会真正进行删除。

在系统运行一段时间之后,就会产生很多的段文件,这样对搜索效率十分不利,Lucene由一个段合并的机制,会自动将一些小的段文件合并为一个较大的段文件,不断重复这样的过程,使段文件保存在一个合适的水平。段合并是一个高硬盘IO的过程,会对索引过程产生影响。默认会选择合并代价最小的文件进行合并,当文件达到一定大小之后,是不会自动进行合并的,因为合并这样的大文件会严重影响系统的正常响应的。ES提供了一个optimize的机制,进行optimize就是对大的段文件进行合并。在5.x后改为_forcemerge。

为了保证索引的建立成功和失败恢复,ES在写入索引的同时和写入translog,这个tanslog在索引写入失败的时候可以对索引进行恢复,有点像数据库的事务

search

搜索过程比较容易理解,上面提到,每一个shard其实就是一个独立的Lucene系统,在查询的时候就是汇总所有节点的结果,产生最终的结果。如我们要搜索前10个命中的结果,则每一个节点先查出自己的索引中的前十的数据,然后发给负责汇总的节点。汇总节点从来自其他节点的前十个命中的结果中选出最终的前十的命中结果,然后返回给客户端。从上面可以看出,当shard的数量比较多的时候,会减慢查询速度,另一个问题就是深层查询,如果我们要找第10000~10010的命中结果,则每一个节点都要给汇总节点发送前10010的命中结果。

启动

启动的过程只要是集群的建立过程,当一个节点启动之后,会主动去ping其他的节点,同时也包括自己,而要去ping那些节点,则可以是可以进行配置的。当有多个master存在的时候,会自动进行选举。当zenDiscover配置不当的时候,很容易出现脑裂的情况,即集群存在多个master,节点分为多个集群,这是我们都不想看到的情况。我们可以通过配置成为master最小需要的票数来决定,从而避免脑裂,一般配置为(master节点数/2)+1

恢复

恢复就是当节点出现故障的情况。索引的状态有3中,绿色,黄色和红色。绿色表示主分片,副分片都正常,此时可以提供服务,黄色表示主分片或者副分片不可用,此时会进行分片恢复,此时可以提供服务,红色表示分片完全丢失,查询的时候不会得到储存在此分片上的数据。

当master节点出现故障时,就会重新进行选举,这个很好理解,当得到的票数不够最小票数的时候,集群就会停止对外提供服务。

当data节点出现故障时,即分片丢失,此时会从副分片中选出一个分片成为主分片,并等待一段时间,看故障节点能否恢复,当超过一段时间之后,还是没有恢复,就会在其他节点上重建副分片,当建立完成之后,则会恢复正常。

总结

到这里对ES集群大概有一个简单的认识,慢慢来,不急不急。


参考资料:

Last modification:September 7th, 2018 at 08:21 pm
If you think my article is useful to you, please feel free to appreciate

Leave a Comment