dubbo线程池资源耗尽的分析
二月份的工作总结,分享一下。
近期我们线上A网站爬取效率不高,时间比较长,由于元旦时可以达到30w+一天,故排查重点还是流程以及dubbo线程池问题。
1、dubbo线程池发生:RejectedExecutionException: Thread pool is EXHAUSTED!异常时,使用jstat查看jvm使用情况,GCT的时间在2-3之间,不算太高。
2、使用jstack查看堆栈信息,发现大量java.lang.Thread.State: RUNNABLE,没有死锁发生。对比A网站和B网站的堆栈信息,A网站java.lang.Thread.State: RUNNABLE比例大概是85%以上,其余是TIMED_WAITING和WAITING;而B网站java.lang.Thread.State: RUNNABLE比例大概是10%~20%,其余是TIMED_WAITING和WAITING。(事后分析,这里已经有问题了,大部分的任务都是RUNNABLE应该是存在问题的)
3、网上查找关于查看dubbo线程池方法。
发现可以使用telnet命令来查看dubbo线程池(http://alibaba.github.io/dubbo-doc-static/Telnet+Command+Reference-zh-showComments=true&showCommentArea=true.htm)
如图所示:
可以查看线程池的健康程度、最大线程数、活跃线程数、任务数等等。
发现当A网站的线程池active是一直波浪增长的,直至达到max,即线程池满了。但查看爬虫自服务、B网站等,active数基本都是1,会增长也会落下来。
至此,基本上可以判断A网站效率问题是由于某种原因导致活跃线程数无法释放,导致最终线程池卡死。
4、由于A网站爬虫有四个定时器启动,分别是a功能、b功能、c功能、d功能,所以分开试验,只启动单个定时器,看active数据是否增长。
a、启动a功能定时器,不增长;
b、启动b功能定时器,缓慢增长;
c、启动c功能定时器,增长较快;
d、启动d功能定时器,不增长。
对比代码,发现b、c中均包含httpClient调用,问题出在httpClient调用。
5、由于B网站也使用了httpClient调用,但并没有出现问题,故需要测试使用代理IP和不使用代理IP两种。
写测试代码测试httpClient调用时使用代理IP与不使用代理IP,发现访问B网站、百度等网站,不使用代理IP,active不增长;使用代理IP访问裁判文书则active增长。怀疑httpClient有些操作导致了线程池资源耗尽。(事后发现此处可以不测试,因为A网站与B网站除了使用与与不使用代理IP外,最大的区别是B网站几乎不超时,而A网站大概率超时)
6、网上查找原因,看了http://blog.csdn.net/clementad/article/details/75649625 这篇文章后发现httpClient的超时设置少了一个,应该增加如下所示: dubbo线程池资源耗尽的分析 - 在路上的小海贼 - 笑傲江湖
运行代码后发现索然active还是有些增长,但明显慢了很多,在家里运行了将近3个小时,从最开始涨到了50左右,然后基本稳定
7、我一个同事后来发现timeout时间设置没有生效,在httpClient.execute()之前,需要设置配置生效,httpget.setConfig(requestConfig);这样设置后,运行一晚上,active数稳定在20左右。后来发现是由于setDefaultRequestConfig两次,第二次set时可能是冲掉了第一次的timeout设置。之所以配置clientBuilder.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(30000).build()); 也能够达到效果,但效果不如使用httpget.setConfig(requestConfig);设置效果明显,是因为前者相当于给httpClient设置了一个超时时间的设置,会起效果,但也只是给响应设置了超时时间,而缺少下面三个配置,则效果不够理想
//客户端和服务器建立连接的timeout
requestConfigBuilder.setConnectTimeout(30000);
//从连接池获取连接的timeout
requestConfigBuilder.setConnectionRequestTimeout(30000);
//连接建立后,request没有回应的timeout
requestConfigBuilder.setSocketTimeout(30000);
8、测试环境和最终的线上环境,同时配置了四个超时时间且都是生效的,这样,长期运行下active数量峰值可达到100以上,但会回落,可以回落到个位数十位数,比较稳定。
9、dubbo线程池稳定后,A网站爬取的效率则得到了提升,目前速度比较稳定,需要长期观察爬取速度和dubbo线程池active数量。