1、报错堆栈
Caused by: org.apache.http.ContentTooLongException: entity content is too long [186516227] for the configured buffer limit [104857600]
at org.elasticsearch.client.HeapBufferedAsyncResponseConsumer.onEntityEnclosed(HeapBufferedAsyncResponseConsumer.java:76) ~[elasticsearch-rest-client-7.7.1.jar!/:7.7.1]
at org.apache.http.nio.protocol.AbstractAsyncResponseConsumer.responseReceived(AbstractAsyncResponseConsumer.java:137) ~[httpcore-nio-4.4.13.jar!/:4.4.13]
2、从报错内容来看,es客户端收到了响应,但是响应的Content-length超过了100M的限制达到了177M导致抛出异常,详见org.elasticsearch.client.HeapBufferedAsyncResponseConsumer#onEntityEnclosed
@Override
protected void onEntityEnclosed(HttpEntity entity, ContentType contentType) throws IOException {
long len = entity.getContentLength();
if (len > bufferLimitBytes) {
throw new ContentTooLongException("entity content is too long [" + len +
"] for the configured buffer limit [" + bufferLimitBytes + "]");
}
if (len < 0) {
len = 4096;
}
this.buf = new SimpleInputBuffer((int) len, getByteBufferAllocator());
this.response.setEntity(new ContentBufferEntity(entity, this.buf));
}
3、这个es查询只是一个简单的统计TOP10的一个业务,但是返回的内容为什么会这么大,直接用命令调es接口发现响应也是很小的
4、因为问题只在生产环境有,arthas又看不出来什么特别的,只能直接用tcpdump抓包看调http的请求响应报文到底是什么样子的,请求报文如下,直接使用请求报文中的请求体调es也确实返回了大量的数据。到这里问题其实比较清晰了,经过对比我手动请求es的命令里面没有带size,而程序请求es的报文里面带了size,导致将文档内容在hits中响应了回来,导致响应超大
POST /index/_search HTTP/1.1
Content-Length: 642
Content-Type: application/json
Connection: Keep-Alive
{
"aggregations": {
"field": {
"terms": {
"field": "field",
"min_doc_count": 1,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
],
"size": 10
}
}
},
"from": 0,
"query": {
"bool": {
}
},
"size": 10000,
"version": true
}
5、接下来看代码里面为什么会带上size为10000,这里可能是我的使用的方式不正确,带上size的地方是在org.springframework.data.elasticsearch.core.RequestFactory#prepareSearchRequest中
6、不纠结根本的改,就是查询的时候显式指定一下size为0,但是因为在org.springframework.data.domain.AbstractPageRequest#AbstractPageRequest中有限制size必须大于0,所以size指定成1可以临时解决这个问题。(因为这里使用es的方式不是直接使用spring原生方式,而是自己包装了一层,根本原因可能还是自己的包装的实现里面有一些不合适的地方,用search去做searchAggregationsCount,search内就会走上兜底size为10000的逻辑,当然直接使用开源的spring方式集成可能也会有类似的问题)