1、ES导出报错CircuitBreakingException[[FIELDDATA] Data too large, data for [proccessDate] would be larger than limit of [10307921510/9.5gb]]
2、ES导出丢失数据,只返回范围内部分数据,同时未报错
ES在查询时,会将索引数据缓存在内存(JVM)中。
当缓存数据到达驱逐线时,会自动驱逐掉部分数据,把缓存保持在安全的范围内。当用户准备执行某个查询操作时,缓存数据+当前查询需要缓存的数据量到达断路器限制时,会返回Data too large错误,阻止用户进行这个查询操作。ES把缓存数据分成两类,FieldData和其他数据,我们接下来详细看FieldData,它是造成我们这次异常的“元凶”。
ES配置中提到的FieldData指的是字段数据。当排序(sort),统计(aggs)时,ES把涉及到的字段数据全部读取到内存(JVM Heap)中进行操作。相当于进行了数据缓存,提升查询效率。
indices.fielddata.cache.size
控制分配给fielddata多少堆内存。当在一个字段首次执行查询时,es会把它加载到内存中,同时添加到fielddata。如果fielddata超过了指定的堆内存,会从fielddata占用的内存中删除掉一些值。但是默认,这个设置是undounded,也就是没限制。这样,fielddata就会一直增加。但是,一旦它占用的内存超过了断路器规定的内存,就不会往里面加载更多fielddata了。
indices.breaker.fielddata.limit
fielddata断路器默认限制fielddata占用堆内存的60%
indices.breaker.request.limit
请求断路器,估算请求或者聚合占用内存大小,默认限制大小为堆内存的40%
indices.breaker.total.limit
默认情况下,total断路器保证请求和fielddata断路器的和小与堆内存的70%
断路器的设置可以在config/elasticsearch.yml
中设置,也可以动态更新:
PUT /_cluster/settings
{
"persistent" : {
"indices.breaker.fielddata.limit" : "40%"
}
}
当fielddata断路器的大小超过设置的值,就会出现开头提到的Data too large。
Data too large异常是ES默认配置的一个坑,我们没有配置indices.fielddata.cache.size
,它就不回收缓存了。缓存到达限制大小,无法往里插入数据。
当前fieldData缓存区大小 < indices.fielddata.cache.size
当前fieldData缓存区大小+下一个查询加载进来的fieldData < indices.breaker.fielddata.limit
fielddata.limit的配置需要比fielddata.cache.size稍大。而fieldData缓存到达fielddata.cache.size的时候就会启动自动清理机制。
indices.breaker.request.limit限制查询的其他部分需要用的内存大小。indices.breaker.total.limit
限制总(fieldData+其他部分)大小。
修改vi /home/elasticsearch-6.1.3/config/elasticsearch.yml
增加
indices.fielddata.cache.size: 60%
indices.breaker.fielddata.limit: 70%
重启服务即可
下面这条可以不加
bootstrap.memory_lock: true
elasticsearch官网建议生产环境需要设置bootstrap.memory_lock: true
官网的解释 是:发生系统swapping的时候ES节点的性能会非常差,也会影响节点的稳定性。所以要不惜一切代价来避免swapping。swapping会导致Java GC的周期延迟从毫秒级恶化到分钟,更严重的是会引起节点响应延迟甚至脱离集群。
所以最好限制住elasticsearch占用的内存情况,可选少用swap
开启bootstrap.memory_lock: true
后,在Elasticsearch集群启动的时候,会报如下错误
ERROR: bootstrap checks failed memory locking requested for elasticsearch process but memory is not locked
方案1:
此方案适用于非systemd管理的linux发行版,centos 6及以下可以仅通过这个方案解决
临时解决
ulimit -l unlimited
永久解决
root权限编辑/etc/security/limits.conf
vi /etc/security/limits.conf
添加如下内容,保存退出
* soft memlock unlimited
* hard memlock unlimited
这里的*代表的是所有用户名称,可以更换为指定用户名
另:这里有个坑就是如果/etc/security/limits.d文件夹下的有配置文件,那么会覆盖刚才修改的文件,所以请确保该目录没有其它文件,如有请联系运维人员确认删除
编辑/etc/sysctl.conf
sudo echo "vm.swappiness=0" >> /etc/sysctl.conf
这个参数的作用是告诉Linux内核尽少的使用swap分区,不等于禁用swap,通过少使用swap来提高性能。
如果想立即生效而不是重启之后让sysctl.conf生效,请使用sysctl -p
重新登录或重启服务器方可生效
方案2:
适用于systemd管理的发行版,有文章提到centos 7需要使用此方案,本人使用debian 9.9.0 亲测解决问题,推荐先完成上边的方案后尝试本方案
这里还是推荐使用上边方法的第3步,尽少使用swap分区
在Centos7系统中,使用Systemd替代了之前的SysV。/etc/security/limits.conf文件的配置作用域缩小了。/etc/security/limits.conf的配置,只适用于通过PAM认证登录用户的资源限制,它对systemd的service的资源限制不生效。因此登录用户的限制,通过/etc/security/limits.conf与/etc/security/limits.d下的文件设置即可。
对于systemd service的资源设置,则需修改全局配置,全局配置文件放在/etc/systemd/system.conf和/etc/systemd/user.conf,同时也会加载两个对应目录中的所有.conf文件/etc/systemd/system.conf.d/.conf和/etc/systemd/user.conf.d/.conf。system.conf是系统实例使用的,user.conf是用户实例使用的。
全局生效方式
vi /etc/systemd/system.conf
在最下方添加
DefaultLimitNOFILE=65536
DefaultLimitNPROC=32000
DefaultLimitMEMLOCK=infinity
保存, 重启系统
局部生效方式:(针对包管理器安装elasticsearch的形式)
sudo systemctl edit elasticsearch
此命令会在/etc/systemd/system下创建elasticsearch.service.d/override.conf文件
添加如下内容
[Service]
LimitMEMLOCK=infinity
保存,退出,执行如下命令生效
sudo systemctl daemon-reload
保存, 重启系统