elasticsearch遇到的问题(二) 慢查询的可能原因

本文探讨了Elasticsearch集群慢查询的诊断方法与优化策略,包括调整shards大小、优化term查询、改进聚合查询等多个方面。

1、首先确定集群的健康

1)_cat/health?v

2)检查集群健康的cpu ,io,内存,磁盘等指标是否都正常

2、慢查询可能的原因(case by case)

2.1 shards大小不合理

遇到这么一个案例:

1、客户反馈es集群存在很多慢查询,检查发现都是term查询,而且进行了sort排序,但是size是top 15,这样的查询不至于一直报慢查询。

2、继续检查日志,发现所有慢查询都是一个索引报的,也就是其他的索引的查询都是正常的

3、定位到索引后,_cat/shards/index_name?v  。五个分片一个副本,shards的store:58G。大小不合理,导致慢查询,建议reindex索引,增加分片数。删除旧索引,给新索引建以旧索引名称为名的别名。

tips:reindex期间,索引仍能都能写,reindex启动的那一刹会定格一个快照,所以建议reindex期间,建议停止索引的写入。避免新旧索引数据不一。

reindex会对源索引的有一定的io开销,相当读取源索引的所有数据再写入到新的索引中,建议尽量在业务低峰期做操作。

2.2 term的字段是数值类型,查询字段非常庞大

数值型byte、short、integer、long做term查询构造docid集合的bitset很费时

如果数值字段没有range需求,改为或者再插入一个keyword类型字段https://elasticsearch.cn/article/446, 如果是cardinality聚合&高基数,可以写入时提前prehash(https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-cardinality-aggregation.html#_pre_computed_hashes)

PS:是否逻辑 的byte字段建议直接用boolean,不过byte类型的额外好处是如果需要true/ false之外的第三种状态,扩展更方便;如果继续使用byte类型,参考: 数值字段(long/ integer)没有range和agg聚合需求,改为或者再插入一个keyword类型字段

按照:https://elasticsearch.cn/article/446

2.3 prefix、wildcard、regexp

通配符和正则表达式、模糊查询,需要遍历倒排索引中的词条列表来找到所有的匹配词条,然后逐个词条地收集对应的文档id

慢日志出现prefix、wildcard、regexp避免使用左通配这样的模式匹配(如: *foo 或 .*foo 这样的正则式;对于部分输入即提示的应用场景,可以考虑优先使用completion suggester, phrase/term suggeter一类性能更好,模糊程度略差的方式查询(https://elasticsearch.cn/article/171);考虑用ngram tokenizer替代(https://www.elastic.co/guide/en/elasticsearch/reference/6.7/analysis-ngram-tokenizer.html#analysis-ngram-tokenizer) 和 (https://wjw465150.github.io/Elasticsearch/3_2_DeepSearch.html#%E8%B6%8A%E8%BF%91%E8%B6%8A%E5%A5%BD)

2.4 agg聚合查询

agg,聚合文档多,多重聚合、条件复杂,深度翻页,from和size很大

优化聚合, 查看collect mode 、execution hint和Minimum document count小结  https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html

2.5 from和size大于10000

深翻页,需要对每个shard的返回的数据整合取top,总条数是shards* (from+size),非常消耗cpu和内存

用 scroll或search_after替代(http://doc.codingdict.com/elasticsearch/109/, http://doc.codingdict.com/elasticsearch/117/)

2.6 script,此外hot_thread显示消耗在script上

script,脚本性能相对低些.

避免使用脚本计算动态字段,建议在索引时计算并在文档中添加该字段;避免进行复杂的计算

2.7 nested, mapping中也有nested

nested查询, 对doc的每一个nested field都会生成一个独立的document, 这将使doc数量剧增,影响查询效率。

2.8 has_child或has_parent, mapping中也有_parent

parent-child查询,适合适合于父文档少、子文档多的情况,比nested慢5到10倍(https://www.elastic.co/guide/cn/elasticsearch/guide/current/parent-child-performance.html

ps:抄自大佬的文章,我自己也是没有吃透的。mark一下

<think>嗯,用户问的是Elasticsearch启动时减少内存可能遇到的问题。看来用户对ES的内存管理有一定了解,但可能在实际操作中遇到了困难。从用户引用的资料来看,ta已经知道ES是Java应用,内存管理很重要,但想了解具体减少内存后的风险。 用户可能正在尝试优化ES集群的资源使用,或者想在资源有限的环境(比如开发机)运行ES。ta的深层需求应该是“如何在保证基本可用的前提下最小化内存占用”。不过从专业角度看,盲目减少内存很危险,需要帮ta分析清楚利弊。 结合引用内容,ES内存问题主要涉及几个层面:JVM堆内存(引用3)、缓存机制(引用2)、熔断器(引用2)和底层Lucene(引用3)。用户提到的“减少启动内存”应该是指调低-Xms参数,但实际影响会波及整个内存体系。 最直接的三个风险点:一是OOM崩溃,因为-Xmx可能设得太低;是频繁GC导致性能雪崩;三是缓存失效引发磁盘IO飙升。特别是引用2提到的fielddata缓存,如果堆内存不足,ES会不断驱逐缓存,聚合排序操作就会变慢。 另外用户没提到但很重要的一点:内存过小会触发熔断器(引用2),导致查询被拒绝。这在生产环境是灾难性的。还有segment合并(引用2)也需要足够内存缓冲,否则会拖累写入速度。 建议从实际场景出发:如果是本地开发,可以适当减内存,但要监控GC日志;如果是生产环境,绝对不要牺牲内存稳定性。引用1强调的“合理配置、监控和优化”正是关键——减少内存的前提是做好监控和评估。 最后要提醒用户,ES 7.0后新增的堆外内存机制(如Frozen Index)对低内存配置更友好,但仍有硬性限制。与其盲目减内存,不如优化索引设计(比如避免引用4提到的自定义ID问题)。</think>以下是Elasticsearch启动时减少内存配置(`-Xms`/`-Xmx`)可能引发的问题及技术解析,结合引用内容分析: --- ### **核心问题与风险** #### 1. **频繁GC导致性能崩溃** - **机制**: 堆内存过小 → 对象分配空间不足 → JVM频繁触发Full GC(尤其是老年代GC) ```mermaid graph LR A[内存不足] --> B[频繁Full GC] B --> C[GC停顿时间激增] C --> D[节点响应延迟] D --> E[集群稳定性下降] ``` - **引用支持**: > "ES是JAVA应用,就离不开JVM和GC" [^3]。 > 堆内存不足时,GC线程会抢占CPU资源,导致查询/索引吞吐量骤降。 #### 2. **缓存失效引发磁盘I/O飙升** - **关键缓存影响**: | **缓存类型** | **内存不足时的行为** | **后果** | |--------------------|-------------------------------|---------------------------| | **Fielddata Cache** | 被迫频繁驱逐数据 (LRU机制) | 聚合/排序操作变慢10-100倍 | | **Query Cache** | 缓存命中率下降 | 重复查询响应延迟增加 | | **OS Filesystem Cache** | Lucene索引文件无法缓存到内存 | 磁盘I/O成为性能瓶颈 | - **引用支持**: > "field data缓存需要占用内存...占用过的内存资源" [^2]。 > 当`indices.fielddata.cache.size`因堆内存不足而缩小时,高频聚合操作会直接访问磁盘。 #### 3. **熔断器触发服务拒绝** - **熔断机制**: ```bash indices.breaker.fielddata.limit # Fielddata熔断阈值 (默认堆的40%) indices.breaker.total.limit # 总内存熔断阈值 (默认堆的70%) ``` - **风险场景**: 若堆内存过小,单个复杂聚合查询即可触发熔断 → 节点拒绝新请求 → 客户端报`CircuitBreakingException` - **引用支持**: > "当内存使用超过一定阈值时,会拒绝新的请求来保护系统稳定性" [^2]。 #### 4. **数据丢失与分片未分配** - **关键风险**: - 内存不足导致JVM崩溃 → 未刷新的数据丢失(即使`translog`存在) - 节点重启后因资源不足无法分配分片 → 集群长期处于`YELLOW`状态 - **示例日志**: ```log [WARN] [o.e.c.r.a.AllocationService] Cluster health status changed to [YELLOW] reason: [shards failed [[index-1][0]]... not enough memory to allocate shard] ``` --- ### **优化建议(平衡内存与稳定性)** #### 1. **最低内存配置原则** - **生产环境**: $$ \text{堆内存最小值} = \max(\text{数据总量} \times 15\%, 4\text{GB}) $$ 例如:100GB数据的集群 → 至少分配15GB堆内存 - **开发/测试环境**: 可设`-Xms1g -Xmx1g`,但需关闭副本: ```bash curl -XPUT 'localhost:9200/_settings' -H 'Content-Type: application/json' -d' {"index.number_of_replicas": 0} ``` #### 2. **关键参数调优** | **参数** | **低内存环境建议值** | **作用** | |----------------------------------|----------------------------|---------------------------| | `indices.fielddata.cache.size` | 10% (e.g. `10%` if heap=2g) | 限制Fielddata缓存上限 | | `indices.queries.cache.size` | 100MB | 控制查询缓存 | | `bootstrap.memory_lock` | `true` | 避免Swap挪用JVM内存 | #### 3. **资源监控与告警** ```bash # 监控关键指标 GET _nodes/stats/jvm,indices?filter_path=nodes.*.jvm.mem.heap_used_percent,nodes.*.indices.fielddata.memory_size ``` - **告警阈值**: - `heap_used_percent > 75%` → 触发扩容评估 - `fielddata.evictions > 100/s` → 需优化聚合查询或扩容 --- ### **总结:减少内存的取舍** > "通过合理的配置、监控和优化,可以有效地管理和排除内存故障" [^1],但需遵循: > 1. **堆内存不得低于4GB**(生产环境),否则GC和熔断风险剧增 > 2. 优先优化**索引设计**(如避免[自定义ID导致的性能损耗](^4)) > 3. 监控**Fielddata驱逐率**和**GC停顿时间**,早于OOM发现问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值