你的httpclient真的使用正确吗

我用java开发类似scrapy的工具包时,在使用httpclient做网络请求,遇到了请求无限卡死的问题,今天将其解决方案拿出来,避免后人踩坑。

问题如下:
RequestConfig.custom().setSocketTimeout(SO_TIME_OUT).setConnectTimeout(CONNECTION_TIME_OUT).setConnectionRequestTimeout(CONNECTION_REQUEST_TIME_OUT)

在设置了常规的超时配置如socketTimeout、connectTimeout和connectionRequestTimeout,在大并发情况下,时不时会出现部分请求在java.net.SocketInputStream.socketRead0方法中一直卡死,dump出的信息如下:

"pool-2-thread-87" #202 prio=5 os_prio=0 tid=0x00007f52603a8000 nid=0x6672 runnable [0x00007f51888c6000]
   java.lang.Thread.State: RUNNABLE
	at java.net.SocketInputStream.socketRead0(Native Method)
	at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
	at java.net.SocketInputStream.read(SocketInputStream.java:171)
	at java.net.SocketInputStream.read(SocketInputStream.java:141)
	at org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:137)
	at org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:153)
	at org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:282)
	at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:138)
	at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
	at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
	at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163)
	at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273)
	at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
	at org.apache.http.impl.execchain.MainClientExec.createTunnelToTarget(MainClientExec.java:486)
	at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:411)
	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:237)
	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
排查自己是否踩坑

可以通过运行命令:jstack -l ${pid} | grep java.net.SocketInputStream.socketRead0
如果多次dump信息都有同一个线程栈每次都出现,则可以判断你的服务也存在这种问题

解决方案
  1. 如果是https的,并且使用的是4.3.5版本的httpclient版本,升级httpclient版本即可,这个是httpclient的bug,详情见https://issues.apache.org/jira/browse/HTTPCLIENT-1589,这是第一种可能性的解决方案。
  2. 如果第一种不能解决,基本都是这种可能性了。我在使用httpclient的代理请求,经过无数次的debug,发现代理请求时在TUNNEL_TARGET步骤,里面的连接用的DefaultBHttpClientConnection绑定的socket,使用的是SocketConfig配置,而不是RequestConfig,所以在没有设置SocketConfig情况下,socket的ocketRead0方法是无限等待的,就会造成线程一直卡死。增加下面的配置即可:
connectionManager.setSocketConfig(SocketConfig.custom().setSoTimeout(SO_TIME_OUT).build());

另外,凡是用到socket的,可能都需要注意是否设置了socket的timeout,不然就会出现一直socketRead0的情况。

本文作者:二当家的
同名博客文章链接: 2018/12/15/你的httpclient真的使用正确吗
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!

二当家的黑板报
扫描上面微信公众号,获取更多技术信息

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值