一:场景复现
我们A服务在调用B服务(订单服务),进行订单查询的时候,B服务查询ES报错。
二:问题排查
1.报错问题
A服务报错msg:
调用订单服务查询异常,参数= {“jumpType”:1,“pageIndex”:1,“pageSize”:2147483647, “saleOrderCode”:[“XXXXXXXXXXXXXXXX”],“searchCount”:true}, result={“code”:“”,“msg”:“Elasticsearch exception [type=search_phase_execution_exception, reason=all shards failed]”,“success”:false}
B服务(订单服务)报错msg:
Elasticsearch exception [type=search_phase_execution_exception, reason=all shards failed]|org.elasticsearch.ElasticsearchStatusException: Elasticsearch exception [type=search_phase_execution_exception, reason=all shards failed] at org.elasticsearch.rest.BytesRestResponse.errorFromXContent(BytesRestResponse.java:177) at org.elasticsearch.client.RestHighLevelClient.parseEntity(RestHighLevelClient.java:2053) at org.elasticsearch.client.RestHighLevelClient.parseResponseException(RestHighLevelClient.java:2030) at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1777) at org.elasticsearch.client.RestHighLevelClient.performRequest(RestHighLevelClient.java:1734) at org.elasticsearch.client.RestHighLevelClient.performRequestAndParseEntity(RestHighLevelClient.java:1696)
2.排查方向
2.1.排查es报错语句,发现是es深度分页不能查询超过10000条。
为什么会这样:
ES分页查询,有一个服务器默认值,为index.max_result_window=10000,即分页查询单次不能超过10000条。
然后A服务传入的pageSizes = Integer.MAX_VALUE(2的31次方 - 1)
所以报错了。
那么如何解决这个报错呢。
首先,我们要了解普通的ES分页查询是怎样的。
假设分页查询,每页size=100,你查询第100页,from和size分别是from=(100 - 1) * 100=9900, size=100,这时ES需要从各个分片上跟别取出10000条数据,如果是3各分片,总共就是3*10000条数据,然后汇总排序、过滤,再取出最终符合条件的100条数据。如果查询 第101页,这时from=10000,ES从各分片取出10100条数据。
那么可知,如果查询数据过大,从ES每个分页的数据查询量就越大,性能指数级下降。
所以,解决办法有两个:
- 把默认值修改为比10000大的数值。
- 查询数据传入小于10000。
前文可知,我们是由于查询的pageSize传入值过大导致的,那么能不能修改ES分页查询默认值,来支持大数量查询呢?
结论:最好不要,因为ES本身分页数据,是从各分片取数据,然后组装,如果查询数据量过大,会导致性能下降,甚至ES崩溃。
如果非要设置,可以通过以下语句设置:
curl -XPUT 192.168.40.31:9200/datasmart/_settings -d ‘{ “index.max_result_window” :“1000000”}’
或者
PUT alarm/_settings { “max_result_window” : 200000000 }
成功返回:
{“acknowledged”:true}
查询相关设置:
curl -XGET 192.168.40.31:9200/datasmart/_settings
或者
GET alarm/_settings { }
所以,我们采用了第二种解决方案,A服务修改查询值为9999