1、昨天线上出了个问题:我们线上的一个爬虫任务一直没有执行完毕,导致后面其他的任务跑的数据出错。发现问题之后,立刻找运维帮忙dump线上机器的日志来看:
我们可以看到线程的状态还是runnable,然后看下线程的是阻塞在了socketRead0,因为之前有遇到过类似的问题就是MySQL的查询语句,从线程池中拿连接的时候没有校验连接的有效性导致拿不到连接,然MySQL的连接超时时间是默认的8小时。导致任务一个无效的线程,拿阻塞了8个小时才断开连接,问题当然是毁灭性的了。当然缺少有效性的校验和超时时间的设置是必要的,但是任务的监控添加也是有必要的。这个后面在说。
今天发生的这个问题是由于DefaultHttpClient这个不推荐使用的客户端引起的,具体我们项目中的代码是这样使用的:
问题就出在这句上面:get.setConfig(RequestConfig.custom().setConnectTimeout(Constant.TIMEOUT)
.setSocketTimeout(Constant.TIMEOUT).build());//10秒钟超时时间
这个超时时间的设置是不对的。我们跟着源码进去,我这里贴出非重要的路径:
当我们跟着源码到DefaultRequestDirector的exectue的方法的时候就差不多要切入正题了。下面咱们具体看看一个特别重要的方法tryConnect,他里面给我们会设置连接的超时时间等信息。
tryConnect是一个内部方法,先检查是否当前连接是否是开启的,没有就会开启,进入到这个open方法中。
可以看到连接是有的上一个方法返回的open属性的值是false。那么就去开启这个连接。结合上一步我们可以知道这个方法是需要设置超时时间等信息的。同事我们也可以看到poolEntry连接池中的信息,创建时间就是我Test启动的时间,超时时间是个特别大的值。
开启的时候最终会走到PlainSocketFactory:
你会发现他是从HttpParams params里面取值的。而不是我们代码中设置的样子。
到此问题找到了,具体的解决办法有没有呢,当然有啊,而且还不只一个:
解决办法:
1.用下面的这种方式设置参数就是OK的啦。因为她就是按照下面的方式取值的么。
2.第二种不用这个废弃的方式了。这种方式呢大家猜也难能猜到了,她设置值的时候是直接加载的config,就是咱们构造的这个socketConfig啦。大家有兴趣就跟进源码中去看看了。
第二章fadebug源码真的很爽。
网友评论