ES官网调优指南

第一局部:调优索引速度

第二局部:调优搜寻速度

第三局部:通用的一些倡议

ES公布时带有的默认值,可为es的开箱即用带来很好的体验。全文搜寻、高亮、聚合、索引文档 等性能无需用户批改即可应用,当你更分明的晓得你想如何应用es后,你能够作很多的优化以进步你的用例的性能,上面的内容通知你 你应该/不应该 批改哪些配置。

第一局部:调优索引速度

https://www.elastic.co/guide/...

应用批量申请批量申请将产生比单文档索引申请好得多的性能。

为了晓得批量申请的最佳大小,您应该在具备单个分片的单个节点上运行基准测试。首先尝试索引100个文件,而后是200,而后是400,等等。当索引速度开始稳固时,您晓得您达到了数据批量申请的最佳大小。在配合的状况下,最好在太少而不是太多文件的方向上犯错。请留神,如果群集申请太大,可能会使群集受到内存压力,因而倡议防止超出每个申请几十兆字节,即便较大的申请看起来成果更好。

发送端应用多worker/多线程向es发送数据 发送批量申请的单个线程不太可能将Elasticsearch群集的索引容量最大化。为了应用集群的所有资源,您应该从多个线程或过程发送数据。除了更好地利用集群的资源,这应该有助于升高每个fsync的老本。

请确保留神TOOMANYREQUESTS(429)响应代码(Java客户端的EsRejectedExecutionException),这是Elasticsearch告诉您无奈跟上以后索引速率的形式。产生这种状况时,应该再次尝试暂停索引,现实状况下应用随机指数回退。

与批量调整大小申请相似,只有测试能力确定最佳的worker数量。这能够通过逐步减少工作者数量来测试,直到集群上的I / O或CPU饱和。

1.调大 refresh interval

默认的index.refresh_interval是1s,这迫使Elasticsearch每秒创立一个新的分段。减少这个价值(比如说30s)将容许更大的局部flush并缩小将来的合并压力。

2.加载大量数据时禁用refresh和replicas

如果您须要一次加载大量数据,则应该将index.refreshinterval设置为-1并将index.numberofreplicas设置为0来禁用刷新。这会临时使您的索引处于危险之中,因为任何分片的失落都将导致数据 失落,然而同时索引将会更快,因为文档只被索引一次。初始加载实现后,您能够将index.refreshinterval和index.numberofreplicas设置回其原始值。

3.设置参数,禁止OS将es过程swap进来

您应该确保操作系统不会swapping out the java过程,通过禁止swap (https://www.elastic.co/guide/...)

4.为filesystem cache调配一半的物理内存

文件系统缓存将用于缓冲I / O操作。您应该确保将运行Elasticsearch的计算机的内存至多缩小到文件系统缓存的一半。

5.应用主动生成的id(auto-generated ids)

索引具备显式id的文档时,Elasticsearch须要查看具备雷同id的文档是否曾经存在于雷同的分片中,这是低廉的操作,并且随着索引增长而变得更加低廉。通过应用主动生成的ID,Elasticsearch能够跳过这个查看,这使索引更快。

6.买更好的硬件

搜寻个别是I/O 密集的,此时,你须要

  1. 为filesystem cache调配更多的内存
  2. 应用SSD硬盘
  3. 应用local storage(不要应用NFS、SMB 等remote filesystem)
  4. 亚马逊的 弹性块存储(Elastic Block Storage)也是极好的,当然,和local storage比起来,它还是要慢点

如果你的搜寻是 CPU-密集的,买好的CPU吧

7.加大 indexing buffer size

如果你的节点只做大量的索引,确保index.memory.indexbuffersize足够大,每个分区最多能够提供512 MB的索引缓冲区,而且索引的性能通常不会进步。Elasticsearch采纳该设置(java堆的一个百分比或相对字节大小),并将其用作所有流动分片的共享缓冲区。十分沉闷的碎片天然会应用这个缓冲区,而不是执行轻量级索引的碎片。

默认值是10%,通常很多:例如,如果你给JVM 10GB的内存,它会给索引缓冲区1GB,这足以承载两个索引很重的分片。

8.禁用fieldnames字段

fieldnames字段引入了一些索引工夫开销,所以如果您不须要运行存在查问,您可能须要禁用它。(fieldnames:https://www.elastic.co/guide/...)

9.剩下的,再去看看 “调优 磁盘应用”吧

(https://www.elastic.co/guide/...)中有许多磁盘应用策略也进步了索引速度。

第二局部-调优搜寻速度

1.filesystem cache越大越好

为了使得搜寻速度更快, es重大依赖filesystem cache

一般来说,须要至多一半的 可用内存 作为filesystem cache,这样es能够在物理内存中 保有 索引的热点区域(hot regions of the index)

2.用更好的硬件

搜寻个别是I/O bound的,此时,你须要

  • 为filesystem cache调配更多的内存
  • 应用SSD硬盘
  • 应用local storage(不要应用NFS、SMB 等remote filesystem)
  • 亚马逊的 弹性块存储(Elastic Block Storage)也是极好的,当然,和local storage比起来,它还是要慢点

如果你的搜寻是 CPU-bound,买好的CPU吧

3.文档模型(document modeling)

文档须要应用适合的类型,从而使得 search-time operations 耗费更少的资源。咋作呢?答:防止 join操作。具体是指

  • nested 会使得查问慢 好几倍
  • parent-child关系 更是使得查问慢几百倍

如果 无需join 能解决问题,则查问速度会快很多

4.预索引 数据

依据“搜寻数据最罕用的形式”来最优化索引数据的形式

举个例子:所有文档都有price字段,大部分query 在 fixed ranges 上运行 range aggregation。你能够把给定范畴的数据 事后索引下。而后,应用 terms aggregation

5.Mappings(能用 keyword 最好了)

数字类型的数据,并不意味着肯定非得应用numeric类型的字段。

一般来说,存储标识符的 字段(书号ISBN、或来自数据库的 标识一条记录的 数字),应用keyword更好(integer,long 不好哦,亲)

6.防止运行脚本

一般来说,脚本应该防止。如果他们是相对须要的,你应该应用painless和expressions引擎。

7.搜寻rounded 日期

日期字段上应用now,一般来说不会被缓存。但,rounded date则能够利用上query cache

rounded到分钟等

8.强制merge只读的index

只读的index能够从“merge成 一个独自的 大segment”中收益

9.预热 全局序数(global ordinals)

全局序数 用于 在 keyword字段上 运行 terms aggregations

es不晓得 哪些fields 将 用于/不用于 term aggregation,因而 全局序数 在须要时才加载进内存

但,能够在mapping type上,定义 eagerglobalordinals==true,这样,refresh时就会加载 全局序数

10.预热 filesystem cache

机器重启时,filesystem cache就被清空。OS将index的热点区域(hot regions of the index)加载进filesystem cache是须要破费一段时间的。

设置 index.store.preload 能够告知OS 这些文件须要提前加载进入内存

11.应用索引排序来减速连贯

索引排序对于以较慢的索引为代价来放慢连贯速度十分有用。在索引分类文档中浏览更多对于它的信息。

12.应用preference来优化高速缓存利用率

有多个缓存能够帮忙进步搜寻性能,例如文件系统缓存,申请缓存或查问缓存。然而,所有这些缓存都保护在节点级别,这意味着如果间断运行两次雷同的申请,则有一个或多个正本,并应用循环(默认路由算法),那么这两个申请将转到不同的分片正本,阻止节点级别的缓存帮忙。

因为搜寻应用程序的用户一个接一个地运行相似的申请是常见的,例如为了剖析索引的较窄的子集,应用标识以后用户或会话的优选值能够帮忙优化高速缓存的应用。

13.正本可能有助于吞吐量,但不会始终存在

除了进步弹性外,正本能够帮忙进步吞吐量。例如,如果您有单个分片索引和三个节点,则须要将正本数设置为2,以便共有3个分片正本,以便应用所有节点。

当初假如你有一个2-shards索引和两个节点。在一种状况下,正本的数量是0,这意味着每个节点领有一个分片。在第二种状况下,正本的数量是1,这意味着每个节点都有两个碎片。哪个设置在搜寻性能方面体现最好?通常状况下,每个节点的碎片数少的设置将会更好。

起因在于它将可用文件系统缓存的份额进步到了每个碎片,而文件系统缓存可能是Elasticsearch的1号性能因子。同时,要留神,没有正本的设置在产生单个节点故障的状况下会呈现故障,因而在吞吐量和可用性之间进行衡量。

那么复制品的数量是多少?如果您有一个具备numnodes节点的群集,那么numprimaries总共是主分片,如果您心愿可能一次解决maxfailures节点故障,那么正确的正本数是max(maxfailures,ceil(numnodes / numprimaries) - 1)。

14.关上自适应正本抉择

当存在多个数据正本时,elasticsearch能够应用一组称为自适应正本抉择的规范,依据蕴含分片的每个正本的节点的响应工夫,服务工夫和队列大小来抉择数据的最佳正本。这能够进步查问吞吐量并缩小搜寻量大的应用程序的提早。

第三局部:通用的一些倡议

1、不要 返回大的后果集

es设计来作为搜索引擎,它十分善于返回匹配query的top n文档。但,如“返回满足某个query的 所有文档”等数据库畛域的工作,并不是es最善于的畛域。如果你的确须要返回所有文档,你能够应用Scroll API

2、防止 大的doc。即,单个doc 小了 会更好

given that(思考到) http.maxcontextlength默认==100MB,es回绝索引操作100MB的文档。当然你能够进步这个限度,但,Lucene自身也有限度的,其为2GB 即便不思考下面的限度,大的doc 会给 network/memory/disk带来更大的压力;

  • 任何搜寻申请,都须要获取 _id 字段,因为filesystem cache工作形式。即便它不申请 _source字段,获取大doc _id 字段耗费更大
  • 索引大doc时耗费内存会是 doc自身大小 的好几倍
  • 大doc的 proximity search, highlighting 也更加低廉。它们的耗费间接取决于doc自身的大小

3、防止 稠密

  • 不相干数据 不要 放入同一个索引
  • 一般化文档构造(Normalize document structures)
  • 防止类型
  • 在 稠密 字段上,禁用 norms & doc_values 属性

稠密为什么不好?

Lucene背地的数据结构 更善于解决 紧凑的数据

text类型的字段,norms默认开启;numerics, date, ip, keyword,docvalues默认开启 Lucene外部应用 integer的docid来标识文档 和 外部API交互。

举个例子:应用match查问时生成docid的迭代器,这些docid被用于获取它们的norm,以便计算score。以后的实现是每个doc中保留一个byte用于存储norm值。获取norm值其实就是读取doc_id地位处的一个字节

这十分高效,Lucene通过此值能够快速访问任何一个doc的norm值;但,给定一个doc,即便某个field没有值,仍须要为此doc的此field保留一个字节

docvalues也有同样的问题。2.0之前的fielddata被当初的docvalues所代替了。

稠密性 最显著的影响是 对存储的需要(任何doc的每个field,都须要一个byte);然而呢,稠密性 对 索引速度和查问速度 也是有影响的,因为:即便doc并没有某些字段值,但,索引时,仍然须要写这些字段,查问时,须要skip这些字段的值

某个索引中领有大量稠密字段,这齐全没有问题。但,这不应该成为常态

稠密性影响最大的是 norms&docvalues ,但,倒排索引(用于索引 text以及keyword字段),二维点(用于索引geopoint字段)也会受到较小的影响

如何防止稠密呢?

1、不相干数据 不要 放入同一个索引 给个tip:索引小(即:doc的个数较少),则,primary shard也要少

2、一般化文档构造(Normalize document structures)

3、防止类型(Avoid mapping type) 同一个index,最好就一个mapping type。在同一个index上面,应用不同的mapping type来存储数据,听起来不错,但,其实不好。given that(思考到)每一个mapping type会把数据存入 同一个index,因而,多个不同mapping type,各个的field又互不雷同,这同样带来了稠密性 问题

4、在 稠密 字段上,禁用 norms & doc_values 属性

  • norms用于计算score,无需score,则能够禁用它(所有filtering字段,都能够禁用norms)
  • docvlaues用于sort&aggregations,无需这两个,则能够禁用它 然而,不要草率的做出决定,因为 norms&docvalues无奈批改。只能reindex

秘诀1:混合 准确查问和提取词干(mixing exact search with stemming)

对于搜寻利用,提取词干(stemming)都是必须的。例如:查问 skiing时,ski和skis都是冀望的后果

但,如果用户就是要查问skiing呢?

解决办法是:应用multi-field。同一份内容,以两种不同的形式来索引存储 query.simplequerystring.quotefieldsuffix,居然是 查问齐全匹配的

秘诀2:获取一致性的打分

score不能重现 同一个申请,间断运行2次,但,两次返回的文档程序不统一。这是相当坏的用户体验

如果存在 replica,则就可能产生这种事,这是因为:search时,replication group中的shard是按round-robin形式来抉择的,因而两次运行同样的申请,申请如果打到 replication group中的不同shard,则两次得分就可能不统一

那问题来了,“你不是终日说 primary和replica是in-sync的,是完全一致的”嘛,为啥打到“in-sync的,完全一致的shard”却算出不同的得分?

起因就是标注为“已删除”的文档。如你所知,doc更新或删除时,旧doc并不删除,而是标注为“已删除”,只有等到 旧doc所在的segment被merge时,“已删除”的doc才会从磁盘删除掉

索引统计(index statistic)是打分时十分重要的一部分,但,因为 deleted doc 的存在,在同一个shard的不同copy(即:各个replica)上 计算出的 索引统计 并不统一

集体了解:

  • 所谓 索引统计 应该就是df,即 doc_freq
  • 索引统计 是基于shard来计算的

搜寻时,“已删除”的doc 当然是 永远不会 呈现在 后果集中的 索引统计时,for practical reasons,“已删除”doc 仍然是统计在内的

假如,shard A0 刚刚实现了一次较大的segment merge,而后移除了很多“已删除”doc,shard A1 尚未执行 segment merge,因而 A1 仍然存在那些“已删除”doc

于是:两次申请打到 A0 和 A1 时,两者的 索引统计 是显著不同的

如何躲避 score不能重现 的问题?应用 preference 查问参数

收回搜寻申请时候,用 标识字符串 来标识用户,将 标识字符串 作为查问申请的preference参数。这确保屡次执行同一个申请时候,给定用户的申请总是达到同一个shard,因而得分会更为统一(当然,即便同一个shard,两次申请 跨了 segment merge,则仍然会得分不统一)

这个形式还有另外一个长处,当两个doc得分统一时,则默认按着doc的 外部Lucene doc id 来排序(留神:这并不是es中的 _id 或 _uid)。然而呢,shard的不同copy间,同一个doc的 外部Lucene doc id 可能并不相同。因而,如果总是达到同一个shard,则,具备雷同得分的两个doc,其程序是统一的

score错了

score错了(Relevancy looks wrong)

如果你发现

  • 具备雷同内容的文档,其得分不同
  • 齐全匹配 的查问 并没有排在第一位 这可能都是由 sharding 引起的
  • 默认状况下,搜寻文档时,每个shard本人计算出本人的得分。
  • 索引统计 又是打分时一个十分重要的因素。

如果每个shard的 索引统计类似,则 搜寻工作的很好

文档是平分到每个primary shard的,因而 索引统计 会十分类似,打分也会按着预期工作。但,万事都有个然而:

  • 索引时应用了 routing(文档不能平分到每个primary shard 啦)
  • 查问多个索引
  • 索引中文档的个数 非常少

这会导致:参加查问的各个shard,各自的 索引统计 并不类似(而,索引统计对 最终的得分 又影响微小),于是 打分出错了(relevancy looks wrong)

那,如何绕过 score错了(Relevancy looks wrong)?

如果数据集较小,则,只应用一个primary shard(es默认是5个),这样两次查问 索引统计 不会变动,因此得分也就统一啦

另一种形式是,将searchtype设置为:dfsquerythenfetech(默认是querythenfetch)

dfsquerythen_fetch的作用是

  • 向 所有相干shard 发出请求,要求 所有相干shard 返回针对以后查问的 索引统计
  • 而后,coordinating node 将 merge这些 索引统计,从而失去 merged statistics
  • coordinating node 要求 所有相干shard 执行 query phase,于是 发出请求,这时,也带上 merged statistics。这样,执行query的shard 将应用 全局的索引统计

大部分状况下,要求 所有相干shard 返回针对以后查问的 索引统计,这是十分cheap的。但,如果查问中 蕴含 十分大量的 字段/term查问,或者有 fuzzy查问,此时,获取 索引统计 可能并不cheap,因为 为了失去 索引统计 可能 term dictionary 中 所有的term都须要被查问一遍

英文原文:https://www.elastic.co/guide/...

译者:Ghost Stories

起源:http://wangnan.tech/post/elas...

近期热文举荐:

1.1,000+ 道 Java面试题及答案整顿(2021最新版)

2.别在再满屏的 if/ else 了,试试策略模式,真香!!

3.卧槽!Java 中的 xx ≠ null 是什么新语法?

4.Spring Boot 2.5 重磅公布,光明模式太炸了!

5.《Java开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞+转发哦!