当前位置:首页 » 服务存储 » lucene磁盘存储
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

lucene磁盘存储

发布时间: 2023-03-23 18:52:26

㈠ lucene创建了索引,是不是已经等于缓存了所有数据了

看来楼主是刚接触lucene。

  1. lucene在磁盘上建立的索引,就是数据内容的本身,索引一旦建立,就和数据库没有任何关系了。按楼主的说法就是:已经包含了全部的内容。

  2. lucene的数据是不是缓存到本地,这个问题要看自己的设置。在建立索引的时候,有两种方式,一个是在内存中建立索引,一个是在本地磁盘建立索引。第一种方式,当电脑重启之后就会消失。第二种方式是在本地磁盘建立了文件,可以被长期保留。

㈡ Elasticsearch之存储原理

倒排索引被写入磁盘后是不可变的,ES解决不变性和更新索引的方式是使用多个索引,利用新增的索引来反映修改,在查询时从旧的到新的依次查询,最后来一个结果合并。

ES底层是基于Lucene,最核心的概念就是 Segment(段) ,每个段本身就是一个倒排索引。

ES中的Index由多个段的集合和 commit point(提交点) 文件组成。

提交点文件中有一个列表存放着所有已知的段,下面是一个带有1个提交点和3个段的Index示意图:

Doc会先被搜集到内存中的Buffer内,这个时候还无法被搜索到,如下图所示:

每隔一段时间,会将buffer提交,在flush磁盘后打开新段使得搜索可见,详细过程如下:

下面展示了这个过程完成后的段和提交点的状态:

通过这种方式,可以使得新文档从被索引到可被搜索间的时间间隔在数分钟,但是还不够快。因为磁盘需要 fsync ,这个就成为性能瓶颈。我们前面提到过Doc会先被从buffer刷入段写入文件系统缓存(很快),那么就自然想到在这个阶段就让文档对搜索可见,随后再被刷入磁盘(较慢)。

Lucene支持对新段写入和打开,可以使文档在没有完全刷入硬盘的状态下就能对搜索可见,而且是一个开销较小的操作,可以频繁进行。

下面是一个已经将Docs刷入段,但还没有完全提交的示意图:

我们可以看到,新段虽然还没有被完全提交,但是已经对搜索可见了。

引入refresh操作的目的是提高ES的实时性,使添加文档尽可能快的被搜索到,同时又避免频繁fsync带来性能开销,依靠的就是文件系统缓存OS cache里缓存的文件可以被打开(open/reopen)和读取,而这个os cache实际是一块内存区域,而非磁盘,所以操作是很快的,这就是ES被称为近实时搜索的原因。

refresh默认执行的间隔是1秒,可以使用 refreshAPI 进行手动操作,但一般不建议这么做。还可以通过合理设置 refresh_interval 在近实时搜索和索引速度间做权衡。

index segment刷入到os cache后就可以打开供查询,这个操作是有潜在风险的,因为os cache中的数据有可能在意外的故障中丢失,而此时数据必备并未刷入到os disk,此时数据丢失将是不可逆的,这个时候就需要一种机制,可以将对es的操作记录下来,来确保当出现故障的时候,已经落地到磁盘的数据不会丢失,并在重启的时候可以从操作记录中将数据恢复过来。elasticsearch提供了translog来记录这些操作,结合os cached segments数据定时落盘来实现数据可靠性保证(flush)。

文档被添加到buffer同时追加到translog:

进行 refresh 操作,清空buffer,文档可被搜索但尚未 flush 到磁盘。translog不会清空:

每隔一段时间(例如translog变得太大),index会被flush到磁盘,新的translog文件被创建,commit执行结束后,会发生以下事件:

下面示意图展示了这个状态:

translog记录的是已经 在内存生成(segments)并存储到os cache但是还没写到磁盘的那些索引操作 (注意,有一种解释说,添加到buffer中但是没有被存入segment中的数据没有被记录到translog中,这依赖于写translog的时机,不同版本可能有变化,不影响理解),此时这些新写入的数据可以被搜索到,但是当节点挂掉后这些未来得及落入磁盘的数据就会丢失,可以通过trangslog恢复。

当然translog本身也是磁盘文件,频繁的写入磁盘会带来巨大的IO开销,因此对translog的追加写入操作的同样操作的是os cache,因此也需要定时落盘(fsync)。translog落盘的时间间隔直接决定了ES的可靠性,因为宕机可能导致这个时间间隔内所有的ES操作既没有生成segment磁盘文件,又没有记录到Translog磁盘文件中,导致这期间的所有操作都丢失且无法恢复。

translog的fsync是ES在后台自动执行的,默认是每5秒钟主动进行一次translog fsync,或者当translog文件大小大于512MB主动进行一次fsync,对应的配置是 index.translog.flush_threshold_period 和 index.translog.flush_threshold_size 。

当 Elasticsearch 启动的时候, 它会从磁盘中使用最后一个提交点去恢复已知的段,并且会重放 translog 中所有在最后一次提交后发生的变更操作。

translog 也被用来提供实时 CRUD 。当你试着通过ID来RUD一个Doc,它会在从相关的段检索之前先检查 translog 中最新的变更。

默认 translog 是每5秒或是每次请求完成后被 fsync 到磁盘(在主分片和副本分片都会)。也就是说,如果你发起一个index, delete, update, bulk请求写入translog并被fsync到主分片和副本分片的磁盘前不会反回200状态。

这样会带来一些性能损失,可以通过设为异步fsync,但是必须接受由此带来的丢失少量数据的风险:

flush 就是执行commit清空、干掉老translog的过程。默认每个分片30分钟或者是translog过于大的时候自动flush一次。可以通过flush API手动触发,但是只会在重启节点或关闭某个索引的时候这样做,因为这可以让未来ES恢复的速度更快(translog文件更小)。

满足下列条件之一就会触发冲刷操作:

整体流程:

删除一个ES文档不会立即从磁盘上移除,它只是被标记成已删除。因为段是不可变的,所以文档既不能从旧的段中移除,旧的段也不能更新以反映文档最新的版本。

ES的做法是,每一个提交点包括一个 .del 文件(还包括新段),包含了段上已经被标记为删除状态的文档。所以,当一个文档被做删除操作,实际上只是在 .del 文件中将该文档标记为删除,依然会在查询时被匹配到,只不过在最终返回结果之前会被从结果中删除。ES将会在用户之后添加更多索引的时候,在后台进行要删除内容的清理。

文档的更新操作和删除是类似的:当一个文档被更新,旧版本的文档被标记为删除,新版本的文档在新的段中索引。
该文档的不同版本都会匹配一个查询,但是较旧的版本会从结果中删除。

通过每秒自动刷新创建新的段,用不了多久段的数量就爆炸了,每个段消费大量文件句柄,内存,cpu资源。更重要的是,每次搜索请求都需要依次检查每个段。段越多,查询越慢。

ES通过后台合并段解决这个问题。ES利用段合并的时机来真正从文件系统删除那些version较老或者是被标记为删除的文档。被删除的文档(或者是version较老的)不会再被合并到新的更大的段中。

可见,段合并主要有两个目的:

ES对一个不断有数据写入的索引处理流程如下:

合并过程如图:

从上图可以看到,段合并之前,旧有的Commit和没Commit的小段皆可被搜索。

段合并后的操作:

合并完成后新的段可被搜索,旧的段被删除,如下图所示:

注意 :段合并过程虽然看起来很爽,但是大段的合并可能会占用大量的IO和CPU,如果不加以控制,可能会大大降低搜索性能。段合并的optimize API 不是非常特殊的情况下千万不要使用,默认策略已经足够好了。不恰当的使用可能会将你机器的资源全部耗尽在段合并上,导致无法搜索、无法响应。

㈢ ElasticSearch数据存储内容

很多使用Elasticsearch的同学会关心数据存储在ES中的存储容量,会有这样的疑问:xxTB的数据入到ES会使用多少存储空间。这个问题其实很难直接回答的,只有数据写入ES后,才能观察到实际的存储空间。比如同样是1TB的数据,写入ES的存储空间可能差距会非常大,可能小到只有300~400GB,也可能多到6-7TB,为什么会造成这么大的差距呢?究其原因,我们来探究下Elasticsearch中的数据是如何存储。文章中我以Elasticsearch 2.3版本为示例,对应的lucene版本是5.5,Elasticsearch现在已经来到了6.5版本,数字类型、列存等存储结构有些变化,但基本的概念变化不多,文章中的内容依然适用。

Elasticsearch对外提供的是index的概衡塌庆念,可以类比为DB,用咐握户查询是在index上完成的,衫皮每个index由若干个shard组成,以此来达到分布式可扩展的能力。比如下图是一个由10个shard组成的index。

shard是Elasticsearch数据存储的最小单位,index的存储容量为所有shard的存储容量之和。Elasticsearch集群的存储容量则为所有index存储容量之和。

一个shard就对应了一个lucene的library。对于一个shard,Elasticsearch增加了translog的功能,类似于HBase WAL,是数据写入过程中的中间数据,其余的数据都在lucene库中管理的。

所以Elasticsearch索引使用的存储内容主要取决于lucene中的数据存储。

下面我们主要看下lucene的文件内容,在了解lucene文件内容前,大家先了解些lucene的基本概念。

lucene包的文件是由很多segment文件组成的,segments_xxx文件记录了lucene包下面的segment文件数量。每个segment会包含如下的文件。

下面我们以真实的数据作为示例,看看lucene中各类型数据的容量占比。

写100w数据,有一个uuid字段,写入的是长度为36位的uuid,字符串总为3600w字节,约为35M。

数据使用一个shard,不带副本,使用默认的压缩算法,写入完成后merge成一个segment方便观察。

使用线上默认的配置,uuid存为不分词的字符串类型。创建如下索引:

首先写入100w不同的uuid,使用磁盘容量细节如下:

可以看到正排数据、倒排索引数据,列存数据容量占比几乎相同,正排数据和倒排数据还会存储Elasticsearch的唯一id字段,所以容量会比列存多一些。

35M的uuid存入Elasticsearch后,数据膨胀了3倍,达到了122.7mb。Elasticsearch竟然这么消耗资源,不要着急下结论,接下来看另一个测试结果。

我们写入100w一样的uuid,然后看看Elasticsearch使用的容量。

这回35M的数据Elasticsearch容量只有13.2mb,其中还有主要的占比还是Elasticsearch的唯一id,100w的uuid几乎不占存储容积。

所以在Elasticsearch中建立索引的字段如果基数越大(count distinct),越占用磁盘空间。

我们再看看存100w个不一样的整型会是如何。

从结果可以看到,100w整型数据,Elasticsearch的存储开销为13.6mb。如果以int型计算100w数据的长度的话,为400w字节,大概是3.8mb数据。忽略Elasticsearch唯一id字段的影响,Elasticsearch实际存储容量跟整型数据长度差不多。

我们再看一下开启最佳压缩参数对存储空间的影响:

结果中可以发现,只有正排数据会启动压缩,压缩能力确实强劲,不考虑唯一id字段,存储容量大概压缩到接近50%。

我们还做了一些实验,Elasticsearch默认是开启_all参数的,_all可以让用户传入的整体json数据作为全文检索的字段,可以更方便的检索,但在现实场景中已经使用的不多,相反会增加很多存储容量的开销,可以看下开启_all的磁盘空间使用情况:

开启_all比不开启多了40mb的存储空间,多的数据都在倒排索引上,大约会增加30%多的存储开销。所以线上都直接禁用。

然后我还做了其他几个尝试,为了验证存储容量是否和数据量成正比,写入1000w数据的uuid,发现存储容量基本为100w数据的10倍。我还验证了数据长度是否和数据量成正比,发现把uuid增长2倍、4倍,存储容量也响应的增加了2倍和4倍。在此就不一一列出数据了。

文件名为:segments_xxx

该文件为lucene数据文件的元信息文件,记录所有segment的元数据信息。

该文件主要记录了目前有多少segment,每个segment有一些基本信息,更新这些信息定位到每个segment的元信息文件。

lucene元信息文件还支持记录userData,Elasticsearch可以在此记录translog的一些相关信息。

文件后缀:.si

每个segment都有一个.si文件,记录了该segment的元信息。

segment元信息文件中记录了segment的文档数量,segment对应的文件列表等信息。

文件后缀:.fnm

该文件存储了fields的基本信息。

fields信息中包括field的数量,field的类型,以及IndexOpetions,包括是否存储、是否索引,是否分词,是否需要列存等等。

文件后缀:.fdx, .fdt

索引文件为.fdx,数据文件为.fdt,数据存储文件功能为根据自动的文档id,得到文档的内容,搜索引擎的术语习惯称之为正排数据,即doc_id -> content,es的_source数据就存在这

索引文件记录了快速定位文档数据的索引信息,数据文件记录了所有文档id的具体内容。

索引后缀:.tip,.tim

倒排索引也包含索引文件和数据文件,.tip为索引文件,.tim为数据文件,索引文件包含了每个字段的索引元信息,数据文件有具体的索引内容。

5.5.0版本的倒排索引实现为FST tree,FST tree的最大优势就是内存空间占用非常低 ,具体可以参看下这篇文章: http://www.cnblogs.com/bonelee/p/6226185.html

http://examples.mikemccandless.com/fst.py?terms=&cmd=Build+it 为FST图实例,可以根据输入的数据构造出FST图

生成的 FST 图为:

文件后缀:.doc, .pos, .pay

.doc保存了每个term的doc id列表和term在doc中的词频

全文索引的字段,会有.pos文件,保存了term在doc中的位置

全文索引的字段,使用了一些像payloads的高级特性才会有.pay文件,保存了term在doc中的一些高级特性

文件后缀:.dvm, .dvd

索引文件为.dvm,数据文件为.dvd。

lucene实现的docvalues有如下类型:

其中SORTED_SET 的 SORTED_SINGLE_VALUED类型包括了两类数据 : binary + numeric, binary是按ord排序的term的列表,numeric是doc到ord的映射。

㈣ ElasticSearch部署架构和容量规划

前面介绍了ElasticSearch原理和使用相关的内容,在生产环境如何比较科学的进行容量规划、部署、调优、排查问题呢,业界和官方也对相关的问题进行总结,我这边也结合自己的经验对这些使用ElasticSearch经常遇到的问题进行了总结。其中主要包括以下三大模块:

ElasticSearch有多种类型的节点,在前面概述和核心也已经介绍过了。在这里可以重新回顾下。ElasticSearch的部署节点类型如下:

主节点及其候选节点,负责集群状态(cluster state)的管理

配置项:node.master,默认为true

数据节点,负责数据存储及处理客户端请求

配置项:node.data,默认为true

ingest节点,负责数据处理,脚本执行

配置项:node.ingest,默认为true

协调节点

配置项:设置上面三个参数全部为false,那么它就是一个纯协调节点

机器学习节点,收费属于x-pack

在生产环境部署推荐配置整体思路就是:尽量是一个节点只承担一个角色。

因为不同的节点所需要的计算机资源都不一样。职责分离后可以按需扩展互不影响。

资源要求:中高CPU;中高内存;中低磁盘

一般在生产环境中配置3台

一个集群只有1台活跃的主节点,负责分片管理,索引创建,集群管理等操作

资源要求:CPU、内存、磁盘要求都高

资源要求:高配置CPU;中等配置的RAM;低配置的磁盘

资源要求:一般中高CPU;中高内存;低磁盘

协调节点扮演者负载均衡、结果的聚合,在大型的es集群中条件允许可以使用高配的cpu和内存。因为如果客户端发起了深度分页等请求可能会导致oom,这个在之前也有过分析。

注意:

如果和数据节点或者Coordinate节点混合部署,数据节点本来相对有比较大的内存占用。

而Coordinate节点有时候可能会有开销很高的查询导致OOM,这些甚至都有可能影响Master节点,导致集群的不稳定。

搭建一个es集群是由模式可循的。

这是一个基础版的职责分离的部署架构:

但是如果大量的聚合查询等操作,这种架构不太适合了。

当系统中有大量的复杂查询或者聚合时候,我们可增加Coordinating节点,增加查询的性能,这里增加了负载均衡层,通过负载均衡扩展时应用程序无感知。

这样部署部署相互影响,写入多的话,多部署ingetst节点,读的时候聚合查询较多可以多部署协调节点,存储数据量大,可以适当对数据节点进行调优。

我们知道数据有冷热之分,比如写入频繁的日志数据,近期的索引将会频繁写入。es根据数据这些特征引入了hot节点和warm节点。

使用ssd,该节点上的索引不断的有新文档写入和查询,对cpu、io的要求较高。

可以使用HDD,上面的索引不会有写入,查询较少。上面只保存只读索引或者旧索引,使用大容量便宜的机械硬盘。

配置步骤:

针对多机房灾备,ElasticSearch业界有多种不同的通用解决方案:

一个集群中的节点分布在不同的机房

应用程序同时将数据写入两个集群

应用程序先将数据写入消息队列,然后由下游的消费者消费并写入集群

ElasticSearch官方的跨集群复制功能,基于文档操作实现订阅复制

定期将索引备份到外部存储,如hdfs等设备

写请求交给网关,网关实时写入主集群,然后异步写备集群

如下是基于CCR跨集群复制的部署架构,因为篇幅有限,异地多活又是一个很大的话题,其它方案和其细节可以查阅相关资料。

我们知道当es集群的节点数大于索引的分片数时,集群将无法通过水平扩展提升集群的性能。而分片数过多,对于聚合查询以及集群的元数据管理也都有影响。我们可以总结为:

分片数量较多

优点:

缺点:

通常建议一个集群总分片数小于10w。

如何设计分片的数量呢?一个分片保持多大的数据量比较合适呢?

我们需要根据使用场景来设置:

避免使用非常大的分片,因为这会对群集从故障中恢复的能力产生负面影响。而每个分片也会消耗相应的文件句柄,内存和CPU资源,分片太多会互相竞争,影响性能。

主分片数一旦确定就无法更改,只能新建创建并对数据进行重新索引(reindex),虽然reindex会比较耗时,但至少能保证你不会停机。所以我们一定要科学的设计分片数。

这里摘录于官方关于分片大小的建议:

主分片与副本都能处理查询请求,它们的唯一区别在于只有主分片才能处理索引请求。副本对搜索性能非常重要,同时用户也可在任何时候添加或删除副本。额外的副本能给带来更大的容量,更高的呑吐能力及更强的故障恢复能力

3.1.3. 小结

根据实际经验我们稍微总结下:

对于数据量较小(100GB以下)的index

对于数据量较大(100GB以上)的index:

综合考虑整个index的shard数量,如果shard数量(不包括副本)超过50个,就很可能引发拒绝率上升的问题,此时可考虑把该index拆分为多个独立的index,分摊数据量,同时配合routing使用,降低每个查询需要访问的shard数量。

关闭交换分区的方法是:

这里是官方的jvm推荐配置链接:

https://www.elastic.co/cn/blog/a-heap-of-trouble

es的节点提供查询的时候使用较多的内存来存储查询缓存,es的lucene写入到磁盘也会先缓存在内存中,我们开启设计这个es节点时需要根据每个节点的存储数据量来进行判断。这里有一个流行的推荐比例配置:

示例:

有一个业务的数据量预估实际有1T,我们把副本设置1个,那么es中总数据量为2T。

这里31G表示的是jvm设置不超过32g否则不会使用java的指针压缩优化了。

前面也提到过,数据节点推荐使用ssd

可以考虑:

写入的目标在于增大写入的吞吐量,这里主要从两个方面进行优化:

这里可以针对myindex索引优化的示例:

首先有几个原则我们需要清楚:

我们可以通过health相关的api进行查看

我们可以使用profile api来定位慢查询。

在查询条件中设置profile为true的参数,将会显示查询经历的细节。

其结果为:

这里会返回一个shards列表。其中:

主要包含了如下信息:

Profile API让我们清楚地看到查询耗时。提供了有关子查询的详细信息,我们可以清楚地知道在哪个环节查询慢,另外返回的结果中,关于Lucene的详细信息也让我们深入了解到ES是如何执行查询的。

ES记录了两类慢日志:

慢搜索日志

用来记录哪些查询比较慢,每个节点可以设置不同的阈值。

之前我们已经详细分析了ES的搜索由两个阶段组成:

慢搜索日志给出了每个阶段所花费的时间和整个查询内容本身。慢搜索日志可以为查询和取回阶段单独设置以时间为单位的阈值,在定义好每个级别的时间后,通过level决定输出哪个级别的日志。

示例如下

前面参考官方链接:

https://www.elastic.co/guide/en/elasticsearch/reference/7.17/index-moles-slowlog.html

如果出现节点占用CPU很高,我们需要知道CPU在运行什么任务,一般通过线程堆栈来查看。

这里有两种方式可以查看哪些线程CPU占用率比较高:

这里推荐使用hot_threads api

通过返回的结果可以看到什么线程占用更高,正在做什么操作。更详细的内容可以参考官网:

https://www.elastic.co/guide/en/elasticsearch/reference/7.17/cluster-nodes-hot-threads.html

4.3.2 内存使用率过高

1)缓存类型

首先我们需要了解ES中的缓存类型,缓存主要分成如图所示三大类,如下图所示,一个es节点的内存结构:

Node Query Cache(Filter Context)

Shard Query Cache(Cache Query的结果)

Fielddata Cache

Segments Cache

(segments FST数据的缓存),为了加速查询,FST永驻堆内内存,无法被GC回收。该部分内存无法设置大小,长期占用50%~70%的堆内存,只能通过delete index,close index以及force-merge index释放内存

ES底层存储采用Lucene(搜索引擎),写入时会根据原始数据的内容,分词,然后生成倒排索引。查询时,先通过查询倒排索引找到数据地址(DocID)),再读取原始数据(行存数据、列存数据)。

但由于Lucene会为原始数据中的每个词都生成倒排索引,数据量较大。所以倒排索引对应的倒排表被存放在磁盘上。

这样如果每次查询都直接读取磁盘上的倒排表,再查询目标关键词,会有很多次磁盘IO,严重影响查询性能。为了解磁盘IO问题,Lucene引入排索引的二级索引FST[Finite State Transcer]。原理上可以理解为前缀树,加速查询

2)节点的内存查看

3)案例分析

如果节点出现了集群整体响应缓慢,也没有特别多的数据读写。但是发现节点在持续进行Full GC。

常见原因:

Segments个数过多,导致Full GC

我们可以通过查看ElasticSearch的内存分析命令发现:

segments.memory占用很大空间。

解决方案:

Field data cache 过大,导致Full GC

我们可以查看ElasticSearch的内存使用,发现fielddata.memory.size占用很大空间。同时,数据不存在写入和更新,也执行过segments merge。

解决方案:

复杂的嵌套聚合,导致集群Full GC

节点响应缓慢,持续进行Full GC。导出Dump分析。发现内存中有大量 bucket对象,查看日志,发现复杂的嵌套聚合

解决方案:

4)断路器

es有多种断路器,我们可以合理使用,避免不合理操作引发的OOM,每个断路器可以指定内存使用的限制。

关于es的断路器使用可以参考官网文档:

https://www.elastic.co/cn/blog/improving-node-resiliency-with-the-real-memory-circuit-breaker

在排查es问题时,我们会使用一些常见的命令来分析cpu、io、网络等问题。常见的命令如下

我们这里按照1s的频率输出磁盘信息

如果想查看和进程关联的信息,可以使用pidstat或者iotop。

例如,下面为iotop的输出结果

sar命令可以诊断操作系统内存相关情况。

PS:我们需要关闭内存交换,内存交换会严重损害性能

我们知道,操作系统有内核态和用户态,该命令可以输出相关信息

Recv-Q和Send-Q代表该连接在内核中等待发送和接收的数据长度。

如果改数据太多,可能原因为应用程序处理不及时或者对端的数据接收不及时,比如网络拥塞之类

本片文章先介绍了es的部署架构,回顾了es节点类型以及它们的配置方式,也了解了不同类型对硬件的要求不一样。然后总结了几种不同的架构模式,比如基础部署、读写分离、冷热分离、异地多活等架构模式,在生产环境中一般我们推荐读写分离架构模式,如果可以最好加上冷热分离,不过配置可能稍微复杂点。

对于容量规划与调优,首先要明确存储的数据量和使用场景,推荐内存磁盘比为:搜索类比例(1:16),日志类(1:48);比如2T的总数据,搜索如果要保持良好的性能的话,每个节点31*16=496G。每个节点实际有400G的存储空间。那么2T/400G,则需要5个es存储节点,每个节点分片数多少合适,文中也有介绍。副本分片数需要根据我们的容错需求。我们还总结了集群配置和jvm配置相关的优化。

es的使用优化,我们分别总结了写入和查询的优化。写入是其单次数据量、索引refresh、分词等情况都会影响其吞吐量,我们需要根据实际情况来优化。针对于查询,我们可以使用api工具进行分析,分析慢耗时发在在哪一步。当es集群出现异常时,如cpu过高、内存fullgc、卡顿、变红,我们逐一分析了可能的原因和解决办法,同时也介绍了一些常见的诊断工具和监控api。

我们需要先了解es内部运作的原理,这样才能根据实际情况正确的设置集群参数和数据模型,还需要结合实际工作遇到的问题不断的总结经验,才能用好ElasticSearch。

㈤ Lucene 的存储结构概述

lucene的检索算法属于索引检索,即用空间来换取时间,对需要检索的文件、字符流进行全文索引,在检索的时候对索引进行快速的检索,得到检索位置,这个位置记录检索词出现的文件路径或者某个关键词。

lucene 在存储它的全文索引结构时,是有层次结构的,这涉及到5个层次:索引(Index);段(Segment);文档(Document);域(Field);词(Term),他们的关系如下图所示:(lucene 索引存储结构概念图)

下图是Lucene生成的索引的一个实例,右边是对亏橘首这5个层次的描述:

Lucene的索引结构是有层次结构的,主要分以下几个层次:

Lucene的索引结构中销数,即保存了正向信息,也保存了反向信息。

所谓正向信息:

所谓反向信息:

段(Segment) 的控制策略

在建立索引的时候对性能影响最伍如大的地方就是在将索引写入文件的时候, 所以在具体应用的时候就需要对此加以控制:

Lucene默认情况是每加入10份文档(Document)就从内存往index文件写入并生成一个段(Segment) ,然后每10个段(Segment)就合并成一个段(Segment). 这些控制的变量如下:

MaxMergeDocs用于控制一个segment文件中最多包含的Document数.比如限制为100的话,即使当前有10个segment也不会合并,因为合并后的segment将包含1000个文档,超过了限制。

MinMergeDocs用于确定一个当内存中文档达到多少的时候才写入文件,该项对segment的数量和大小不会有什么影响,它仅仅影响内存的使用,进一步影响写索引的效率。

㈥ ES数据存储可靠性和写入流程

https://www.elastic.co/guide/en/elasticsearch/guide/2.x/near-real-time.html
https://www.elastic.co/guide/en/elasticsearch/guide/2.x/merge-process.html

1、数据存储可靠性保证原理

1.1 translog机制

当一个文档写入Lucence后是存储在内存中的,即使执行了refresh操作仍然是在文件系统缓存中,如果此时服务器宕机,那么这部分数据将会丢失

当进行文档写操作时会先将文档写入Lucene,然后写入一份到translog,写入translog是落盘的

tips:如果对可靠性要求不是很高,也可以设置异步落盘,可以提高性能,由配置index.translog.rability和index.translog.sync_interval控制
tips:translog是追加写入,因此性能比较好

先写入Lucene再写入translog。原因是写入Lucene可能会失败,为了减少写入失败回滚的复杂度,因此先写入Lucene

1.2 flush操作

refresh_interval定时触发 或当translog达到index.translog.flush_threshold_size(默认512mb),ES会触发一次flush操作:先执行refresh操作将buffer中的数据生成segment,然后调用lucene的commit方法将所有内存中的segment fsync到磁盘,最后会清空translog中的数据(6.x版本为了实现sequenceIDs,不删除translog) 。

1.3 merge操作
refresh操作会产生大量的小segment,因此产生的每个文件都会消耗文件句柄,内存,CPU 使用等各种资源。更重要的是每个查询请求都要顺序检查每个segment; segment越多检索会越慢.
ES会运行一个检测任务,在后台把近似大小的segment合并成一个新的大segment,并删除旧segment

1.4、多副本机制
ES有多副本机制(默认是1个副本),一个分片的主副分片不能分片在同一个节点上,进一步保证数据的可靠性。

2、ES写索引的流程