【ElasticSearch】索引数据mapping嵌套深度过大导致Stackoverflow问题排查

这篇具有很好参考价值的文章主要介绍了【ElasticSearch】索引数据mapping嵌套深度过大导致Stackoverflow问题排查。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

现象

集群所有数据节点频繁因为StackOverflowError的错误挂掉,启动后还会挂掉,StackOverflowError异常栈如下

[2023-12-22T16:03:44,057][ERROR][o.e.b.ElasticsearchUncaughtExceptionHandler] [xr-data-hdp-dn-rtyarn0725] fatal error in thread [elasticsearch[xr-data-hdp-dn-rtyarn0725][write][T#6]], exiting
java.lang.StackOverflowError: null
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parseProperties(ObjectMapper.java:283) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parseObjectOrDocumentTypeProperties(ObjectMapper.java:237) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parse(ObjectMapper.java:210) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parseProperties(ObjectMapper.java:319) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parseObjectOrDocumentTypeProperties(ObjectMapper.java:237) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parse(ObjectMapper.java:210) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parseProperties(ObjectMapper.java:319) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parseObjectOrDocumentTypeProperties(ObjectMapper.java:237) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parse(ObjectMapper.java:210) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parseProperties(ObjectMapper.java:319) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parseObjectOrDocumentTypeProperties(ObjectMapper.java:237) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parse(ObjectMapper.java:210) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parseProperties(ObjectMapper.java:319) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parseObjectOrDocumentTypeProperties(ObjectMapper.java:237) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parse(ObjectMapper.java:210) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parseProperties(ObjectMapper.java:319) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parseObjectOrDocumentTypeProperties(ObjectMapper.java:237) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parse(ObjectMapper.java:210) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parseProperties(ObjectMapper.java:319) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parseObjectOrDocumentTypeProperties(ObjectMapper.java:237) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parse(ObjectMapper.java:210) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parseProperties(ObjectMapper.java:319) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parseObjectOrDocumentTypeProperties(ObjectMapper.java:237) ~[elasticsearch-7.9.1.jar:7.9.1]
        ...
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parse(ObjectMapper.java:210) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parseProperties(ObjectMapper.java:319) ~[elasticsearch-7.9.1.jar:7.9.1]
        at org.elasticsearch.index.mapper.ObjectMapper$TypeParser.parseObjectOrDocumentTypeProperties(ObjectMapper.java:237) ~[elasticsearch-7.9.1.jar:7.9.1]

处理

通过堆栈可以看出是写入线程池[write]发生的Stackoverflow,并且可能是在解析mapping的过程发生的,通过ObjectMapper类推断是Object类型数据写入导致的。因此通过拉取集群内所有索引的mapping,尝试找出哪个索引的mapping有Object类型的字段,但结果没能找到。
最后,因为这个集群的索引较少,我们通过简单暴力的方法——二分查找停掉作业观察集群状态,来找到问题索引。

问题排查

问题一

为什么会发生Stackoverflow?

栈溢出的堆栈发生在ES服务端处理客户端的写入请求时,在开启dynamic mapping的情况下,如果写入数据包含新的字段配置,需要解析字段配置,解析字段配置的逻辑是递归解析配置对应的JSON数据,当字段类型为嵌套格式(Object/nested)时,递归的次数取决于用户数据的嵌套层数。问题索引的数据嵌套层数过多导致,递归次数过多,进而导致栈溢出。

验证:

测试写入一条多层嵌套的数据,结果中的代码堆栈和现象中发生StackOverflowError的栈相同,出现了多次递归

{

    "o1":{
        "a":{
            "b":{
                "c":{
                    "d":{
                        "e":{
                            "f":{
                                "g":{
                                    "h":{
                                        "j":"ddd"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

代码堆栈:
【ElasticSearch】索引数据mapping嵌套深度过大导致Stackoverflow问题排查,elasticsearch,jenkins,大数据
查看问题索引确实开启了dynamic mapping,并且原始日志确实存在包含大量嵌套结构的数据

问题二

为什么问题索引的mapping中不包含Object类型的字段?
异常堆栈的触发时机为数据写入解析mapping,此时还未将新的mapping更新为索引的mapping,由于解析mapping时发生了Stackoverflow导致ES进程crash,因此索引mapping没有更新,自然问题索引的mapping中不包含Object类型的字段。

问题三

ES侧有nested字段的深度限制(index.mapping.depth.limit),为什么没拦截掉该消息?
该检查在解析字段配置之后,解析字段时就发生了栈溢出,详见下面的代码

private synchronized Map<String, DocumentMapper> internalMerge(Map<String, CompressedXContent> mappings, MergeReason reason) {
        //...省略无关代码...

            try {
                documentMapper =
                    documentParser.parse(type, entry.getValue(), applyDefault ? defaultMappingSourceOrLastStored : null); // 数据的mapping解析
            } catch (Exception e) {
                throw new MapperParsingException("Failed to parse mapping [{}]: {}", e, entry.getKey(), e.getMessage());
            }
        }

        return internalMerge(defaultMapper, defaultMappingSource, documentMapper, reason);// 这里会检查mapping
    }

private synchronized Map<String, DocumentMapper> internalMerge(@Nullable DocumentMapper defaultMapper,
                                                                   @Nullable String defaultMappingSource, DocumentMapper mapper,
                                                                   MergeReason reason) {
        //...省略无关代码...
        boolean hasNested = this.hasNested;
        Map<String, ObjectMapper> fullPathObjectMappers = this.fullPathObjectMappers;

        Map<String, DocumentMapper> results = new LinkedHashMap<>(2);

        if (defaultMapper != null) {
            if (indexSettings.getIndexVersionCreated().onOrAfter(Version.V_7_0_0)) {
                throw new IllegalArgumentException(DEFAULT_MAPPING_ERROR_MESSAGE);
            } else if (reason == MergeReason.MAPPING_UPDATE) { // only log in case of explicit mapping updates
                deprecationLogger.deprecatedAndMaybeLog("default_mapping_not_allowed", DEFAULT_MAPPING_ERROR_MESSAGE);
            }
            assert defaultMapper.type().equals(DEFAULT_MAPPING);
            results.put(DEFAULT_MAPPING, defaultMapper);
        }

            for (ObjectMapper objectMapper : objectMappers) {
            if (reason != MergeReason.MAPPING_RECOVERY) {
                checkTotalFieldsLimit(objectMappers.size() + fieldMappers.size() - metadataMappers.length
                    + fieldAliasMappers.size());
                checkFieldNameSoftLimit(objectMappers, fieldMappers, fieldAliasMappers);
                checkNestedFieldsLimit(fullPathObjectMappers);
                checkDepthLimit(fullPathObjectMappers.keySet()); // 检查mapping的最大深度是打破阈值,是则抛出IllegalArgumentException
            }

            results.put(newMapper.type(), newMapper);
        }


        return results;
    }

解决方法

官方社区在v8.6修复了该问题,https://github.com/elastic/elasticsearch/issues/52098,我们使用的版本是ES7,需要升级或者打patch才能解决文章来源地址https://www.toymoban.com/news/detail-775774.html

生产环境建议

  1. 最好不好开启dynamic mapping功能,不仅影响性能,低版本还可能出现本文的问题
  2. 故障处理时可以考虑临时增加日志,辅助问题排查。像这次问题如果在mapping解析的部分加上索引名或者字段信息辅助找到问题索引,故障时间将大幅缩短
  3. 版本迭代最好跟上社区,很多问题社区都解决了
  4. 该问题排查还可以考虑开启Transport tracer,打印出写入请求日志,看看发生栈溢出之前的写入的索引数据情况

到了这里,关于【ElasticSearch】索引数据mapping嵌套深度过大导致Stackoverflow问题排查的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Elasticsearch 创建索引mapping修改、修复

    背景:原始index名字是indexName,mapping设置错误,且已经有数据进去,想要修改mapping结构 返回结果:表示新建索引成功 下面表示把indexName的数据同步到indexName_1

    2024年02月11日
    浏览(43)
  • Elasticsearch8.8.0 SpringBoot实战操作各种案例(索引操作、聚合、复杂查询、嵌套等)

    Elasticsearch8.8.0 全网最新版教程 从入门到精通 通俗易懂 引入依赖 添加配置文件 application.yaml 导入ca证书到项目中 从任意一个es容器中,拷贝证书到resources目录下 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EXytUrDp-1691330960034)(media/16912196423122/16

    2024年02月13日
    浏览(60)
  • Elasticsearch学习-索引操作及Mapping映射

    在7.X版本前类似于关系型数据库中的数据库概念,8.X版本后删除了type概念,索引类似于关系型数据库中的表 相当于关系型数据库中的一条数据,最小单元 每一个节点就是一个ES实例(一个java进程),一个节点 != 一台服务器 多个节点组成分布式系统,ES原生分布式,已启动一

    2023年04月22日
    浏览(42)
  • 深入理解Elasticsearch的索引映射(mapping)

    当我们谈论Elasticsearch时,索引映射是一个核心概念,它定义了如何存储和检索数据。在Elasticsearch 7.6及更高版本中,映射提供了一系列强大的功能,使您能够精确地控制数据的结构和行为。本文将详细介绍映射的关键属性、用途以及如何正确设置和优化它。 在Elasticsearch中,

    2024年02月22日
    浏览(47)
  • Elasticsearch索引优化指南:分片、副本、mapping和analyzer

    Elasticsearch是一个开源的分布式搜索引擎,它的数据存储和查询速度非常快。然而,在面对大规模的数据集和高并发访问时,Elasticsearch的性能也可能受到一些影响。为了最大程度地提高Elasticsearch的性能,我们需要对索引进行优化。本篇博客将介绍Elasticsearch索引优化的几个关键

    2024年02月20日
    浏览(47)
  • Elasticsearch磁盘占用大于95% 导致索引自动置为只读的解决方法

    应用系统在更新或者插入elasticsearch的时候报错 看错误信息大意是要操作的索引是只读的,不能进行插入或删除。 原因是当Elasticsearch所在磁盘占用大于等于95%时,Elasticsearch会把所有相关索引自动置为只读。(Elasticsearch官方文档有介绍) 解决方案有两种: 1.清理磁盘,使占用

    2024年02月06日
    浏览(46)
  • elementui 表单数据嵌套过深导致校验不了问题解决

    在使用 elementui 表单校验的过程中发现表单中存在嵌套多个层级的数据不能进行校验。 elementui 中如果需要进行表单校验,表单项的 prop 和 v-model 绑定的属性值命名必须要是相同的。而对于多层级的嵌套属性我们应该怎么表示呢? 只需要将表单对象后的字符串作为 prop 的值即

    2024年01月24日
    浏览(51)
  • Elasticsearch(ES)(版本7.x)创建索引报错:Faile to parse mapping [_doc] Root mapping definition has unsupported

    Elasticsearch(ES)(版本7.x)创建索引报错: 因es7.0版本之后不再需要type doc,把上面语句中的doc删掉,再运行就可以创建索引了。 如果还需要type doc则需要增加include_type_name=true即可解决。 示例:

    2024年02月16日
    浏览(43)
  • ElasticSearch创建索引报错:mapper_parsing_exception Root mapping definition has unsupported parameters

    ElasticSearch版本号:5.6.14,这个错误和ES版本有一定的关系,还是先交代下版本号,免得有的读者根据我的方法操作后无效 错误翻译: mapper_parsing_exception :映射解析异常 Root mapping definition has unsupported parameters :根映射定义包含不受支持的参数 错误映射语句1: 错误映射语句

    2024年02月11日
    浏览(56)
  • 【数据库】哪些操作会导致索引失效

    🍎 个人博客: 个人主页 🏆 个人专栏: 数据库 ⛳️   功不唐捐,玉汝于成 目录 前言 正文 结语  我的其他博客   在数据库管理中,索引的有效性对于查询性能至关重要。然而,索引可能会因为各种操作而失效,从而影响到数据库的性能和稳定性。了解导致索引失效的常

    2024年02月19日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包