如何从应用频繁502说起ES的essetTimeout无效问题

如何从应用频繁502说起ES的es setTimeout无效问题,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

为利津等地区用户提供了全套网页设计制作服务,及利津网站建设行业解决方案。主营业务为成都做网站、网站建设、外贸营销网站建设、利津网站设计,以传统方式定制建设网站,并提供域名空间备案等一条龙服务,秉承以专业、用心的态度为用户提供真诚的服务。我们深信只要达到每一位用户的要求,就会得到认可,从而选择与我们长期合作。这样,我们也可以走得更远!

缘起

应用用的ES集群版本是1.7,公司内部让升级版本,说是这个集群版本太老了,由于种种原因没有升级,就这样应用拖到了618,结果在这期间应用频繁的发生502和rpc线程池被打满的情况,给我们本应该顺畅的618带来了一片乌云。

如何从应用频繁502说起ES的es setTimeout无效问题如何从应用频繁502说起ES的es setTimeout无效问题

得到此报警之后,开始dump机器线程,发现有大量的es线程在阻塞,并且有很多的http线程也在阻塞,这也就不难排查发生502和RPC线程池被打满的原因,由于es操作迟迟未返回,导致业务线程池被打满,http连接一直等待结果返回,连接不释放,导致了tomcat接收业务请求也被打满,进而导致应用访问频繁出现502。

如何从应用频繁502说起ES的es setTimeout无效问题

上图就是jstack下来线程,可以看到有大量的http线程被阻塞,然后查看详情,

如何从应用频繁502说起ES的es setTimeout无效问题

详情中有大量的线程被阻塞在了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说起ES的es setTimeout无效问题

改造之后,系统不再抛502异常,线程数也趋于稳定,稳定在了400左右,之前常常是一千多。

如何从应用频繁502说起ES的es setTimeout无效问题

更近一步

由于对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无效问题问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注创新互联行业资讯频道了解更多相关知识。


新闻标题:如何从应用频繁502说起ES的essetTimeout无效问题
路径分享:http://scyanting.com/article/jhcigh.html