【发布时间】:2021-11-16 11:49:19
【问题描述】:
我在 PRD 有一个问题。我们最近发布了一个 springboot 应用程序,它暴露了 REST API。移动/Web APP 调用 Spring [不是 sprintboot] 中的旧 Spring 应用程序,它是一个 Web 应用程序,然后路由并调用新 springboot 中的这些失败的 api。我们只看到这些 api 的超时异常。 从 Spring 遗留 Web 应用程序到其他应用程序还有许多其他 OUTBOUND api 调用,例如:login API [其 api 流量很大,但这些遗留 api 运行良好并调用其他遗留应用程序。 在暴露了这些 REST API 的 springboot 应用程序中没有日志中的异常/错误。事实上,我们只在 Spring Web 应用程序中看到超时 - 意味着连接已用尽,但这并不能解释为什么其他使用相同包装器 HTTPClient 的 apis OUTBOUND 调用没有失败。那些因超时而失败的人在springboot中没有请求日志[显然是因为他们没有离开spring web application tomcat JVM并因超时而死在那里] 因此,如果我们说连接池已用尽,其他大量流量 OUTBOUnd 调用也应该面临同样的问题,但我们没有看到。 所有 API 调用 OUTWARD 使用 HTTPCLient [apache.] 不清楚是什么导致了问题。我还在服务器端的新 springboot 中明确定义了下面[我只是这样做是为了看看这是否有区别,但徒劳无功]:
server:
tomcat:
connection-timeout: 10s
max-connections: 20000
max-threads: 500
min-spare-threads: 10
tomcat Log at spring web applicaiton [caller]:
org.apache.http.conn.ConnectionPoolTimeoutException
org.apache.http.conn.ConnectionPoolTimeoutException.Timeout waiting for connection from pool
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.leaseConnection(PoolingHttpClientConnectionManager.java:313)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager$1.get(PoolingHttpClientConnectionManager.java:279)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:191)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
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:72)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:221)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:165)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:140)
at
任何输入?
Wrapper HTTPClient 的代码 sn-p :
SSLContext sslContext = SSLContexts.createDefault();
HostnameVerifier hostnameVerifier = new DefaultHostnameVerifier();
SSLConnectionSocketFactory secureSSLConnectionSocketFactory = new SSLConnectionSocketFactory(
sslContext,
sslProtocolsArray,
ciphersArray,
hostnameVerifier);
ConnectionSocketFactory nonSecureConnectionSocketFactory = PlainConnectionSocketFactory.getSocketFactory();
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
.<ConnectionSocketFactory>create()
.register("https", secureSSLConnectionSocketFactory)
.register("http", nonSecureConnectionSocketFactory)
.build();
securePoolingConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
securePoolingConnectionManager.setMaxTotal(this.connectionMgrMaxTotalSecure);
securePoolingConnectionManager.setDefaultMaxPerRoute(this.connectionMgrMaxPerRouteSecure);
SocketConfig secureSocketConfig = SocketConfig
.custom()
.setSoKeepAlive(true)
.setTcpNoDelay(true)
.build();
secureHttpsClient = HttpClients
.custom()
.setSSLSocketFactory(secureSSLConnectionSocketFactory)
.setConnectionManager(securePoolingConnectionManager)
.setDefaultRequestConfig(secureRequestConfig)
.setDefaultSocketConfig(secureSocketConfig)
.disableAutomaticRetries()
.build();
上面的堆栈跟踪只是在调用调用的包装器 HTTPClient 方法上失败:
protected String execute(HttpClient httpclient, HttpRequestBase http) throws IOException {
String result;
ResponseHandler<String> responseHandler = new BasicResponseHandler();
result = httpclient.execute(http, responseHandler);
return result;
}
【问题讨论】:
-
您的
HttpClientConnections 池已用尽。你如何创建ClientConnectionManager?你能编辑你的问题并添加堆栈跟踪的其余部分吗? -
我们如何回答所有其他使用相同通用 HTTPClient 包装器的 OUTWARD api 调用工作正常?这些 api 都没有因此错误而失败。
-
这里是来自我们的包装 HTTPClient 类的代码 sn-p:
securePoolingConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); securePoolingConnectionManager.setMaxTotal(this.connectionMgrMaxTotalSecure); securePoolingConnectionManager.setDefaultMaxPerRoute(this.connectionMgrMaxPerRouteSecure); SocketConfig secureSocketConfig = SocketConfig .custom() .setSoKeepAlive(true) .setTcpNoDelay(true) .build(); -
在打印行失败时的堆栈跟踪包装类方法之后。这基本上是调用
protected String execute(HttpClient httpclient, HttpRequestBase http) throws IOException { String result; ResponseHandler<string> responseHandler = new BasicResponseHandler();结果 = httpclient.execute(http, responseHandler);返回结果; }</string> -
请编辑您的问题,而不是在 cmets 中发布代码。
标签: spring spring-boot tomcat