#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 статистики пула, так что я могу видеть количество подключений, которые подтвердили утечку. Поскольку эта вторая оболочка использовалась повторно, и мы использовали ее в этом выпуске, это было подозрительно, и ее удаление решило проблему. Другое дело откопать эту обертку и выяснить, как был обработан пул, но причина была обнаружена.