【问题标题】:ConnectionPoolTimeoutException at caller [spring web applicaiton] logs but no logs at server [springboot]调用者 [spring web application] 记录 ConnectionPoolTimeoutException,但服务器 [springboot] 没有日志
【发布时间】: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


【解决方案1】:

所以我必须挖掘另一个包装器,它也在使用这个 HTTP 池,并被用于我们正在泄漏的遗留系统中。关闭这个。幸运的是,有池统计 api 暴露,所以我可以看到确认泄漏的租用连接数。由于第二个包装器被重新使用并且我们在此版本中使用过,这很可疑,删除它解决了这个问题。挖掘那个包装器并找出池是如何处理的但原因被发现是另一回事。

【讨论】:

    猜你喜欢
    • 2015-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-13
    • 1970-01-01
    • 1970-01-01
    • 2010-11-28
    • 1970-01-01
    相关资源
    最近更新 更多