解决ES-Hadoop拉取ES数据时的circuit_breaking_exception错误
场景概述
通过批处理任务使用ES-Hadoop从每日生成的ES索引(命名为log-22-YYYYMMDD,单索引约500GB)拉取数据,创建24个Hive外部表分别对应每小时数据。
Hive外部表定义
CREATE EXTERNAL TABLE MYDATA.ES_DATA_EXT ( .... column definition here .... ) ROW FORMAT SERDE 'org.elasticsearch.hadoop.hive.EsSerDe' STORED BY 'org.elasticsearch.hadoop.hive.EsStorageHandler' TBLPROPERTIES ( 'es.resource' = 'log-22-YYYYMMDD' , 'es.nodes' = 'x.x.x.x:9200,y.y.y.y:9200' , 'es.mapping.date.rich' = 'false' , 'es.query' = '{ \"query\" : { \"range\" : { \"reg_date\" : { \"gte\" : \"2024-06-27 23:00:00\", \"lt\" : \"2024-06-28 00:00:00\" } } } }' , 'external.table.purge' = 'true' );
(注:原定义存在拼写错误,已修正es.reource为es.resource、exernal.table.purge为external.table.purge)
数据加载执行语句
INSERT OVERWRITE TABLE MYDATA.ES_DATA SELECT * FROM MYDATA.ES_DATA_EXT;
错误信息摘要
Caused by: org.elasticsearch.hadoop.rest.EsHadoopInvalidRequest: org.elasticsearch.hadoop.rest.EsHadoopRemoteException: circuit_breaking_exception: [parent] Data too large, data for [<transport_request>] would be [31759382830/29.5gb], which is larger than the limit of [31621696716/29.4gb], real usage: [31759382072/29.5gb], new bytes reserved: [758/758b], usages [request=0/0b, fielddata=1184131672/1.1gb], in_flight_requests=758/758b, accounting=378111740/360.5mb]
{"query":{"range":{"reg_date":{"gte":"2024-06-27 23:00:00","lt":"2024-06-28 00:00:00"}}}, "_source":["flt1",........,"str9"]}
at org.elasticsearch.hadoop.rest.RestClient.checkResponse(RestClient.java:477)
... 24 more
]], Vertex did not succeed due to OWN_TASK_FAILURE, failedTasks:1 killedTasks:15, Vertex vertex_1716617651513_108904_1_00 [Map 1] killed/failed due to:............................
已知现状
- ES堆内存已调至最大值,问题仍出现
- 错误仅发生在拉取23:00-次日00:00数据时(批处理00:30执行),日间拉取无异常
- 该时段必须使用次日新ES索引,无法更换
解决线索
1. 优化ES-Hadoop拉取参数
- 减小批量拉取大小:在TBLPROPERTIES中添加
'es.batch.size.bytes' = '100mb'(可根据实际调整为50-200MB),降低单次请求的数据量,避免触发熔断 - 限制并发请求数:添加
'es.batch.size.entries' = '1000'和'es.http.max.connections' = '10',减少ES节点同时处理的请求数,缓解内存压力
2. 跨时段查询的分片优化
- 检查数据分布:若23:00-00:00的数据部分落在当日旧索引,拆分查询分别拉取两个索引的数据后再合并,避免单索引扫描过多分片
- 限定分片扫描:如果索引按时间路由或分片,通过
es.routing参数指定目标时段对应的分片,减少不必要的分片扫描
3. Hive任务层面拆分压力
- 增加Map任务数:设置
set mapreduce.job.maps=60;(根据集群资源调整),将拉取任务拆分到更多Map实例,每个Map处理的数据量更小 - 启用并行执行:设置
set hive.exec.parallel=true;,在集群资源充足的前提下提升任务并行度 - 调整Map内存配置:合理设置
mapreduce.map.memory.mb和mapreduce.map.java.opts,避免Map任务占用过多内存导致ES请求堆积
4. ES熔断阈值临时调整(应急方案)
若允许动态调整ES配置,可临时提高父级熔断阈值(注意会增加OOM风险):
PUT /_cluster/settings { "persistent": { "indices.breaker.parent.limit": "90%" } }
后续需结合数据优化调整,不可长期依赖此配置
5. 检查新索引分片状态
00:30执行任务时,次日新索引可能处于分片未完全初始化状态,导致查询内存压力陡增:
- 查看分片健康状态:
GET /log-22-YYYYMMDD/_cluster/health - 在批处理中添加延迟或分片状态检查步骤,等待分片完全分配后再执行拉取任务
内容的提问来源于stack exchange,提问作者SeungCheol Han

