Исключение ConnectionPoolTimeoutException в журналах вызывающего абонента [веб-приложение spring], но без журналов на сервере [springboot]

#spring #spring-boot #tomcat

Вопрос:

У меня есть одна проблема в PRD. недавно мы выпустили приложение springboot, в котором представлен API REST. Мобильное/веб-приложение вызывает устаревшее приложение spring, которое находится в spring [не sprintboot], и это веб-приложение, которое затем направляет и вызывает эти отказывающие API в новой springboot. Мы видим исключение времени ожидания только для этих API . существует множество других ИСХОДЯЩИХ вызовов api, выполняемых из устаревшего веб-приложения spring в другие приложения, например : API входа в систему [который имеет большой трафик api, но эти устаревшие API хорошо работают и вызывают другие устаревшие приложения. В приложениях springboot, в которых есть эти API REST, в журналах нет исключений/ошибок. На самом деле мы видим только тайм-аут в веб-приложении spring-это означает, что соединение исчерпано, но это не объясняет, почему не завершаются исходящие вызовы других API, которые используют ту же оболочку HttpClient. У тех, у кого сбой с таймаутом, нет журналов запросов в springboot [ очевидно, потому что они не покидают JVM spring web application tomcat и не умирают там из-за таймаута], Поэтому, если мы скажем, что пул соединений исчерпан, другие исходящие вызовы с интенсивным трафиком также должны столкнуться с той же проблемой, но мы этого не видим. Все внешние вызовы API используют HttpClient [apache.] Не ясно, что вызывает проблему. Я также явно определил ниже в новой springboot для серверной части [я просто сделал это, чтобы посмотреть, имеет ли это значение, но напрасно]:

 server:
  tomcat:
    connection-timeout: 10s
    max-connections: 20000
    max-threads: 500
    min-spare-threads: 10
 

журнал tomcat в веб-приложении spring [вызывающий абонент]:

 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 
 

Есть какие-нибудь данные?

Фрагмент кода обертки HttpClient :

  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 resu<
        ResponseHandler<String> responseHandler = new BasicResponseHandler();
        result = httpclient.execute(http, responseHandler);
        return resu<
    }
 

Комментарии:

1. Ваш запас HttpClientConnection s исчерпан. Как вы создаете ClientConnectionManager это ? Можете ли вы отредактировать свой вопрос и добавить остальную часть трассировки стека.

2. Как мы можем ответить, что все остальные внешние вызовы api, использующие ту же универсальную оболочку HttpClient, работают нормально? Ни один из этих API-интерфейсов не работает с этой ошибкой.

3. Вот фрагмент кода из нашего класса HttpClient-оболочки: <код> securePoolingConnectionManager = новый пул HttpClientConnectionManager(socketFactoryRegistry); securePoolingConnectionManager.setMaxTotal(это.connectionMgrMaxTotalSecure); securePoolingConnectionManager.setDefaultMaxPerRoute(это.connectionMgrMaxPerRouteSecure); SocketConfig secureSocketConfig = SocketConfig .custom() .setSoKeepAlive(true) .setTcpNoDelay(true) .сборка(); <код></код>

4. После этого выводится метод класса-оболочки stacktrace при сбое строки. который в основном вызывает <код> выполнение защищенной строки(HttpClient httpclient, http HttpRequestBase), вызывает исключение IOException { Результат строки; ResponseHandler<код><Строка> ResponseHandler = new BasicResponseHandler(); результат = httpclient.execute(http, ResponseHandler); возвращает результат; }

5. Пожалуйста, отредактируйте свой вопрос вместо того, чтобы публиковать код в комментариях.

Ответ №1:

Поэтому мне приходится копаться в другой оболочке, которая также использовала этот пул HTTP и использовалась в нашем наследии, которое просачивалось. Закрываю это. К счастью, был открыт API статистики пула, так что я могу видеть количество подключений, которые подтвердили утечку. Поскольку эта вторая оболочка использовалась повторно, и мы использовали ее в этом выпуске, это было подозрительно, и ее удаление решило проблему. Другое дело откопать эту обертку и выяснить, как был обработан пул, но причина была обнаружена.