java httpClient 在默认配置下线程池堆满导致的一次大坑
程序员文章站
2022-07-13 09:37:46
...
最近系统在调用第三方系统时,出现一次严重的报错。导致系统半小时内出错率 timeout 奇高。
## 背景
项目使用 ClonableHttpClient 调用第三方 httpClient v4.5.3,使用时只调用了 connectTimeout, SocketTimeout. 第三方系统因故障导致服务器响应慢,期间出现较多的 ReadTimeout, 持续8分钟,随后恢复,而我们的系统当时正好处于业务高峰期,前端出现大量的 ReadTimeout, 持续了近40分钟。客户要求查原因
## 分析过程
- 系统上线运行了两年了,没有出现大的问题,这种场景的之前也遇到过,重启了事。
- 此次要求查 ROOT CAUSE。主要还是怀疑 httpClient 设置上。系统使用的代码如下
```
CloseableHttpClient httpClient = context.getBean(CloseableHttpClient.class); RequestConfig.Builder builder = RequestConfig.custom(); builder.setAuthenticationEnabled(true); builder.setConnectTimeout(timeout); builder.setSocketTimeout(timeout); StringEntity stringEntity = new StringEntity(params, Charset.forName("UTF-8")); HttpPost post = new HttpPost(address); post.setConfig(builder.build()); post.setHeader("Content-type", "application/json; charset=utf-8"); post.setEntity(stringEntity); HttpEntity httpEntity = httpClient.execute(post).getEntity();
```
基本是缺省配置,想来想去,最后认为应该是在第三方系统故障期间,堆积了大量的请求,进行了排队,即使第三方系统恢复了,入队的请求还要一个个的去消费。
参考 https://gaozzsoft.iteye.com/blog/2352241
httpClient 默认会有一个线程池,默认的并发线程池为5,另中有一配置 setConnectionRequestTimeout 在无配置的情况下,排队的请求 会无限等待。 setConnectionRequestTimeout 可以设置一个等待可用线程池的最大等待时间。我们自行用代码验证这一逻辑,没有看到官方的描述。
设置之后,如果超时,会返回一个错误
```
org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
```