今天在向ES导入数据,通过kibana进行查询时出现[circuit_breaking_exception] [parent] Data too large, data for [<http_request>] would be [1003569608/957mb]
错误,一顿google解决了这个问题,记录一下。
0X01 异常信息
kibana的异常日志如下:
log [15:53:41.570] [error][status][plugin:reporting@7.6.1] Status changed from red to red - [circuit_breaking_exception] [parent] Data too large, data for [<http_request>] would be [1003569608/957mb], which is larger than the limit of [986061209/940.3mb], real usage: [1003569608/957mb], new bytes reserved: [0/0b], usages [request=0/0b, fielddata=6732/6.5kb, in_flight_requests=452608/442kb, accounting=367288473/350.2mb], with { bytes_wanted=1003569608 & bytes_limit=986061209 & durability="PERMANENT" }
环境信息:
Windows 10(Build 18363) + JDK 13.0.2
Elasticsearch 7.6.1 + Logstash 7.6.1 + Kibana 7.6.1 + Metricbeat 7.6.1
0X02 原因及解决方法
Elasticsearch开发者设计了熔断机制,可以通过修改fielddata断路器、request断路器和total的值来调节熔断机制的触发阈值,配置分别是indices.breaker.fielddata.limit
、indices.breaker.request.limit
和indices.breaker.total.limit
fielddata断路器默认设置为jvm堆内存的60%作为上限,request断路器默认设置为jvm堆内存的40%,total的值保证request断路器和fielddata断路器两者组合起来不超过jvm堆内存的70%。断路器的限制可以在文件config/elasticsearch.yml中指定,也可以动态更新一个正在运行的集群。
所以针对"Data too large"这个报错,我们要么清理缓存、要么增大内存
1> 清理filed data cache缓存
curl -XPOST 'http://localhost:9200/fdns/_cache/clear?fielddata=true'
返回结果为:
{"_shards":{"total":10,"successful":5,"failed":0}}
2> 限制filed data cache不要占用过大的jvm堆内存
调用UPDATE _cluster/settings设置indices.fielddata.cache.size参数来限制fileddata缓存不要占用过大的jvm堆内存。设置方法如下:
curl -XPUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d '{
"persistent" : {
"indices.breaker.fielddata.limit" : "40%"
}
}'
将field data调整为40%后查看kibana服务正常,返回值如下:
{
"acknowledged": true,
"persistent": {
"indices": {
"breaker": {
"fielddata": {
"limit": "40%"
}
}
}
},
"transient": {}
}
*如果修改field data值为40%仍然报错,建议设置更小的值试试。
3> 为Elasticsearch jvm设置更大的堆内存
默认ES的jvm堆内存大小设置为1G,这里我们修改为8G,在config/jvm.options中修改:
-Xms8g
-Xmx8g
0X03 fielddata优化最佳实践
fielddata值是用来存储查询信息的缓存,如果你查询一个新的信息时fielddata中未缓存此信息,查询结果的大小超过了field data的使用空间大小,其他的值将会被回收从而获得足够的空间。
默认情况下fielddata的缓存大小设置为unbounded,即Elasticsearch 永远都不会从fielddata中回收数据。这个默认设置是刻意设计成这样的,fielddata并不是临时缓存,它是驻留内存里的数据结构,必须可以快速执行访问,而且构建它的代价十分高昂。如果每个请求都重载数据,性能会十分糟糕。因此我们要为fielddata设置合适的值来优化Elasticsearch并非用这个设置解决内存不够用的问题。
可以通过调节indices.fielddata.cache.size
的值为fielddata分配的堆空间大小,修改config/elasticsearch.yml文件可以实现配置,最佳实践配置如下:
# 避免发生OOM
indices.breaker.total.limit: 70%
# 最久未使用的 fielddata 会被回收
indices.fielddata.cache.size: 25%
# fielddata 断路器
indices.breaker.fielddata.limit: 40%
# request 断路器
indices.breaker.request.limit: 40%
个人增加:
ES_JAVA_OPTS设置大一点