ElasticSearch:从[FIELDDATA]Data too large错误看FieldData配置

本文深入探讨了Elasticsearch中的缓存配置问题,包括FieldData的监控、配置及格式选择等,帮助理解Datatoolarge异常产生的原因及解决办法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 产生Data too large异常

今早运行查询时,ES返回了如下报错:

{
    "error": "... CircuitBreakingException[[FIELDDATA] Data too large, data for [proccessDate] would be larger than limit of [10307921510/9.5gb]]; }]",
    "status": 500

}

再尝试其他查询也是如此。经排查,原来是ES默认的缓存设置让缓存区只进不出引起的,具体分析一下。


2. ES缓存区概述

首先简单描述一下ES的缓存机制。ES在查询时,会将索引数据缓存在内存(JVM)中:
缓存区
上图是ES的JVM Heap中的状况,可以看到有两条界限:驱逐线断路器。当缓存数据到达驱逐线时,会自动驱逐掉部分数据,把缓存保持在安全的范围内。当用户准备执行某个查询操作时,断路器就起作用了,缓存数据+当前查询需要缓存的数据量到达断路器限制时,会返回Data too large错误,阻止用户进行这个查询操作。ES把缓存数据分成两类,FieldData和其他数据,我们接下来详细看FieldData,它是造成我们这次异常的“元凶”。


3. FieldData

ES配置中提到的FieldData指的是字段数据。当排序(sort),统计(aggs)时,ES把涉及到的字段数据全部读取到内存(JVM Heap)中进行操作。相当于进行了数据缓存,提升查询效率。


3.1 监控FieldData

仔细监控fielddata使用了多少内存以及是否有数据被驱逐是非常重要的。

Fielddata缓存使用可以通过下面的方式来监控:

对于单个索引使用 {ref}indices-stats.html[indices-stats API]:

 GET /_stats/fielddata?fields=*

对于单个节点使用 {ref}cluster-nodes-stats.html[nodes-stats API]:

GET /_nodes/stats/indices/fielddata?fields=*

或者甚至单个节点单个索引

GET /_nodes/stats/indices/fielddata?level=indices&fields=*

通过设置 ?fields=* 内存使用按照每个字段分解了.

在产生Data too large异常时,对集群FieldData监控的返回结果如下:
单节点FieldData监控
可以看到memory_size_in_bytes用到了整个JVM内存的60%(可用上限),而evictions(驱逐)为0。且经过一段时间观察,字段所占内存大小都没有变化。由此推断,当下的缓存处于无法有效驱逐的状态


3.2 Cache配置

关于FieldData的配置在elasticsearch.yml中,也可以通过调用setting接口来修改。API文档里的介绍如下:

SettingDescription
indices.fielddata.cache.sizeThe max size of the field data cache, eg 30% of node heap space, or an absolute value, eg 12GB. Defaults to unbounded.
indices.fielddata.cache.expire[experimental] This functionality is experimental and may be changed or removed completely in a future release. A time based setting that expires field data after a certain time of inactivity. Defaults to -1. For example, can be set to 5m for a 5 minute expiry.

简而言之:
indices.fielddata.cache.size 配置fieldData的Cache大小,可以配百分比也可以配一个准确的数值。cache到达约定的内存大小时会自动清理,驱逐一部分FieldData数据以便容纳新数据。默认值为unbounded无限
indices.fielddata.cache.expire用于约定多久没有访问到的数据会被驱逐,默认值为-1,即无限。expire配置不推荐使用,按时间驱逐数据会大量消耗性能。而且这个设置在不久之后的版本中将会废弃。

看来,Data too large异常就是由于fielddata.cache的默认值为unbounded导致的了。


3.3 FieldData格式

除了缓存取大小之外,我们还可以控制字段数据缓存到内存中的格式

在mapping中,我们可以这样设置:

{
    "tag": {
        "type":      "string",
        "fielddata": {
            "format": "fst"
        }
    }
}

对于String类型,format有以下几种:
paged_bytes (默认)

使用大量的内存来存储这个字段的terms和索引。

fst

用`FST`的形式来存储terms。这在terms有较多共同前缀的情况下可以节约使用的内存,但访问速度上比paged_bytes 要慢。

doc_values

fieldData始终存放在disk中,不加载进内存。访问速度最慢且只有在index:no/not_analyzed的情况适用。

对于数字和地理数据也有可选的format,但相对String更为简单,具体可在api中查看。
从上面我们可以得知一个信息:我们除了配置缓存区大小以外,还可以对不是特别重要却量很大的String类型字段选择使用fst缓存类型来压缩大小


4. 断路器

fieldData的缓存配置中,有一个点会引起我们的疑问:fielddata的大小是在数据被加载之后才校验的。假如下一个查询准备加载进来的fieldData让缓存区超过可用堆大小会发生什么?很遗憾的是,它将产生一个OOM异常。
断路器就是用来控制cache加载的,它预估当前查询申请使用内存的量,并加以限制。断路器的配置如下:

indices.breaker.fielddata.limit

这个 fielddata 断路器限制fielddata的大小,默认情况下为堆大小的60%。

indices.breaker.request.limit

这个 request 断路器估算完成查询的其他部分要求的结构的大小, 默认情况下限制它们到堆大小的40%。

indices.breaker.total.limit

这个 total 断路器封装了 request 和 fielddata 断路器去确保默认情况下这2个部分使用的总内存不超过堆大小的70%。

断路器限制可以通过文件 config/elasticsearch.yml 指定,也可以在集群上动态更新:

PUT /_cluster/settings
{
  "persistent" : {
    "indices.breaker.fielddata.limit" : 40% (1)
  }
}

当缓存区大小到达断路器所配置的大小时会发生什么事呢?答案是:会返回开头我们说的Data too large异常。这个设定是希望引起用户对ES服务的反思,我们的配置有问题吗?是不是查询语句的形式不对,一条查询语句需要使用这么多缓存吗?

5. 总结


  1. 这次Data too large异常是ES默认配置的一个坑,我们没有配置indices.fielddata.cache.size,它就不回收缓存了。缓存到达限制大小,无法往里插入数据。个人感觉这个默认配置不友好,不知ES是否在未来版本有所改进。
  2. 当前fieldData缓存区大小 < indices.fielddata.cache.size
    当前fieldData缓存区大小+下一个查询加载进来的fieldData < indices.breaker.fielddata.limit
    fielddata.limit的配置需要比fielddata.cache.size稍大。而fieldData缓存到达fielddata.cache.size的时候就会启动自动清理机制。expire配置不建议使用。

  3. indices.breaker.request.limit限制查询的其他部分需要用的内存大小。indices.breaker.total.limit限制总(fieldData+其他部分)大小。

  4. 创建mapping时,可以设置fieldData format控制缓存数据格式。

http://blog.youkuaiyun.com/yinchunxiang/article/details/39011297
https://www.elastic.co/guide/en/elasticsearch/reference/current/fielddata-formats.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-fielddata.html#index-modules-fielddata

### 关于Elasticsearch .kibana索引迁移失败及Circuit Breaking Exception错误分析 当执行查询操作时,如果返回`circuit_breaking_exception`异常,则表明当前请求的数据量超出了内存限制。此问题通常发生在处理大量数据或复杂聚合时。 #### 错误原因解析 该错误的核心原因是内存分配不足,无法满足请求所需资源。具体表现为: - 数据请求大小超过了预设的断路器限制[^1]。 - 当前可用内存不足以支持新的字节预留需求[^2]。 对于`.kibana`索引迁移失败的情况,可能是因为迁移过程中涉及大量的元数据加载到内存中,而这些元数据未能被有效管理,从而触发了电路保护机制。 #### 解决方案 ##### 调整断路器阈值 可以通过修改集群级别的设置来调整断路器的限制比例。以下是几种常见的参数及其作用: - **Fielddata Limit**: 控制字段数据缓存使用的最大百分比。 ```json PUT /_cluster/settings { "persistent": { "indices.breaker.fielddata.limit": "40%" } } ``` - **Request Limit**: 设置单个请求可占用的最大内存比例。 ```json PUT /_cluster/settings { "persistent": { "indices.breaker.request.limit": "40%" } } ``` - **Total Limit**: 定义整个JVM堆栈可用于断路器系统的总内存上限。 ```json PUT /_cluster/settings { "persistent": { "indices.breaker.total.limit": "70%" } } ``` 上述命令通过HTTP `PUT` 请求发送至Elasticsearch节点地址即可生效[^5]。 ##### 增强硬件资源配置 除了软件层面优化外,还需考虑增加物理机器性能指标如RAM容量等硬性条件改善整体运行环境稳定性[^3]。 另外,在实际应用环境中还应注意定期清理无用索引文件释放存储空间;合理规划分片数量减少跨节点通信开销等问题均有助于缓解此类状况发生概率提升系统健壮度水平。 --- ### 示例代码片段展示如何动态更改配置项 下面提供一段Python脚本用于自动化批量更新多个参数值实例演示效果如下所示: ```python import requests def update_cluster_setting(setting_key, value_percentage): url = "http://<your_es_host>:9200/_cluster/settings" headers = {'Content-Type': 'application/json'} payload = { "persistent": { setting_key: f"{value_percentage}%" } } response = requests.put(url, json=payload, headers=headers) if response.status_code == 200: print(f"Updated {setting_key} to {value_percentage}% successfully.") else: print("Failed to update settings:", response.text) update_cluster_setting('indices.breaker.fielddata.limit', 40) update_cluster_setting('indices.breaker.request.limit', 40) update_cluster_setting('indices.breaker.total.limit', 70) ``` > 注:请替换 `<your_es_host>` 实际部署位置后再测试运行以上程序逻辑功能实现情况! --- ### 结论总结 综上所述,针对 `.kibana` 索引迁移失败伴随有 Circuit Breaker 异常现象主要源于内存消耗过高所致。采取适当措施包括但不限于重新定义各类breaker limits数值范围或者升级服务器规格等方式均可达到预期目标即恢复正常业务流程运转状态。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值