如何从应用频繁502说起ES的es setTimeout无效问题,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
应用用的ES集群版本是1.7,公司内部让升级版本,说是这个集群版本太老了,由于种种原因没有升级,就这样应用拖到了618,结果在这期间应用频繁的发生502和rpc线程池被打满的情况,给我们本应该顺畅的618带来了一片乌云。
得到此报警之后,开始dump机器线程,发现有大量的es线程在阻塞,并且有很多的http线程也在阻塞,这也就不难排查发生502和RPC线程池被打满的原因,由于es操作迟迟未返回,导致业务线程池被打满,http连接一直等待结果返回,连接不释放,导致了tomcat接收业务请求也被打满,进而导致应用访问频繁出现502。
上图就是jstack下来线程,可以看到有大量的http线程被阻塞,然后查看详情,
详情中有大量的线程被阻塞在了ES的调用上,这样问题就很明显了,按理来说问题定位到,那解决就应该很好解决了。可是哪想到这才是痛苦的开始。
联合es中间件组排查es集群,结论没有查到有任何慢日志,说是es集群正常。联系网络组,网络组排查之后网络正常,联系运维组排查机器正常。把所有机器实例都删除掉,重新换了一批机器之后问题依旧。不过通过调用监控,日志,线程和堆栈种种迹象均指向了是es的问题。并且es集群是低版本集群,公司已经声明不再维护,之前没有报这过这个问题,现在频繁发生,猜想应该是es资源被缩减,无维护有部分原因。为了临时解决这个问题,不能让线程无限阻塞,应尽快释放线程,即便没有查到数据,也能快速返回。
FilteredQueryBuilder fqb = QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), boolFilterBuilder); SearchResponse searchResponse = client.prepareSearch(indexName) .setTimeout(TimeValue.timeValueMillis(500)) .setTypes(documentType) .setSearchType(SearchType.QUERY_THEN_FETCH) .setQuery(fqb) .addSort("created", SortOrder.DESC) .setFrom(0).setSize(30) .execute() .actionGet();
关键在于setTimeout(TimeValue.timeValueMillis(500))
这一行,查询时间设置为500毫秒,然后愉快的上线,本以为问题会解决,结果比较打脸,问题依旧!
问题迟迟得不到解决,每天应用报警502,线程满,碰到这种情况只能重启应用,烦不胜烦,并且很怀疑为什么明明设置了超时时间就是不生效。最后只能寻根!由于之前对es了解的并不是那么透彻,认为setTimeout就是查询之后如果多长时间没有返回,则断开查询连接直接返回。实际上并不是这样的,他的意思是在查询es的时候,会查询到多个分片上的数据,当到了设定的时间如果还没有查询完,则把已经查询到的数据返回。即便是这样,这个timeout也是经常失效,在es官方的issue中有具体说到:
Sadly, it is a best effort timeout, its not being checked on all places. Specifically, if you send a query that ends up being rewritten into many terms (fuzzy, or wildcard), that part (the rewrite part) does not check for a timeout.
传送门:Timeout on search not respected
那到底怎么配置才能满足如果在设定时间内查询不到数据就超时,扔出超时异常的这种需求呢。经过查看可以在api查询的最后一步也就说 actionGet()或者get()中设置timeout超时时间 actionGet(timeout) T actionGet(long var1, TimeUnit var3) throws ElasticsearchException;
,这样设置之后如果在设定的时间没有查询到数据,就会抛出timeout的异常,实际上这个超时并不是连接超时,而是处理超时,它的超时逻辑是java异步future的超时。不过这也已经满足了我们的需求。在设定时间内没有处理完毕,会抛出超时的异常。
FilteredQueryBuilder fqb = QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), boolFilterBuilder); SearchResponse searchResponse = client.prepareSearch(indexName) .setTimeout(TimeValue.timeValueMillis(500)) .setTypes(documentType) .setSearchType(SearchType.QUERY_THEN_FETCH) .setQuery(fqb) .addSort("created", SortOrder.DESC) .setFrom(0).setSize(30) .execute() .actionGet(1000);
改造之后,系统不再抛502异常,线程数也趋于稳定,稳定在了400左右,之前常常是一千多。
由于对es超时机制理解的不透特,所以又查询了es的其他超时相关设定。
client连接集群节点超时(client.transport.ping_timeout)
Settings settings = Settings.builder().put("client.transport.sniff", true).build(); TransportClient client = new PreBuiltTransportClient(settings);
client.transport.ping_timeout ,The time to wait for a ping response from a node. Defaults to 5s. 默认5s,client ping命令响应的时间,如果无返回,则认为此节点不可用。如果客户端和集群间网络延迟较大或者连接不稳定,可能需要调大这个值。
scroll中的超时
SearchResponse scrollResp = client.prepareSearch(test) .addSort(FieldSortBuilder.DOC_FIELD_NAME, SortOrder.ASC) .setScroll(new TimeValue(60000)) .setQuery(qb) .setSize(100).get();
scroll里面的时间,这个将启用超时的scroll滚动,经过测试,这个参数应该又是一个薛定谔的参数,没什么作用,还是少依赖它做一些事情吧
关于如何从应用频繁502说起ES的es setTimeout无效问题问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。