Соединение HttpClientConnectionManager не использует повторно TCP-соединение при подключении к конечной точке httpsJAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Соединение HttpClientConnectionManager не использует повторно TCP-соединение при подключении к конечной точке https

Сообщение Anonymous »

Я подключаюсь к службе SOAP с помощью клиента, созданного с помощью Spring WebServiceGatewaySupport. Однако я заметил, что TCP-соединение закрывается после каждого цикла запроса/ответа. В ходе дальнейшего расследования я обнаружил, что соединение закрывается, как только предпринимается еще одна попытка запроса. Такое поведение вызывает проблемы с производительностью из-за частого открытия и закрытия TCP-соединений.
Чтобы решить эту проблему, я попытался использовать собственный HttpClient с включенным повторным использованием соединения, но мне это удалось. не добиться желаемого результата. Ниже приведено краткое описание моей настройки и результатов.
Зависимости

Код: Выделить всё

org.springframework.boot
spring-boot-starter-parent
2.7.18



org.springframework.ws
spring-ws-core


org.springframework.ws
spring-ws-security



org.apache.wss4j
wss4j-ws-security-dom
2.4.0



org.apache.httpcomponents
httpclient


org.apache.httpcomponents
httpcore

Дополнительная информация
Случай 1
Использовать HTTP-соединение с простым HTTP-сервером, работающим локально в контейнере докеров.
Клиентский код

Код: Выделить всё

Registry socketFactoryRegistry = RegistryBuilder.create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.build();

PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
connectionManager.setDefaultSocketConfig(SocketConfig.custom()
.setSoTimeout(2 * 60 * 1000)
.build());

CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.addInterceptorFirst((HttpRequestInterceptor) (request, context) -> {
// Remove Content-Length header to prevent conflict
request.removeHeaders("Content-Length");
})
.setConnectionReuseStrategy((response, context) -> true)
.setDefaultRequestConfig(RequestConfig.custom()
.setExpectContinueEnabled(true)
.setConnectTimeout(2 * 60 * 1000)
.setSocketTimeout(2 * 60 * 1000)
.build())
.setKeepAliveStrategy((response, context) -> 2 * 60 * 1000)
.evictIdleConnections(2, TimeUnit.MINUTES)
.build();

HttpComponentsMessageSender messageSender = new HttpComponentsMessageSender(httpClient);
Журнал запроса №1

Код: Выделить всё

2025-01-15 15:07:57.388 DEBUG 46686 --- [nio-8042-exec-1] org.apache.http.wire                     : http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
2025-01-15 15:07:57.388 DEBUG 46686 --- [nio-8042-exec-1] org.apache.http.wire                     : http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.13)[\r][\n]"
…
2025-01-15 15:07:57.421 DEBUG 46686 --- [nio-8042-exec-1] o.a.http.impl.execchain.MainClientExec   : Connection can be kept alive for 120000 MILLISECONDS
2025-01-15 15:07:57.424 DEBUG 46686 --- [nio-8042-exec-1] h.i.c.PoolingHttpClientConnectionManager : Connection [id: 0][route: {}->localhost:9090] can be kept alive for 120.0 seconds
2025-01-15 15:07:57.425 DEBUG 46686 --- [nio-8042-exec-1] h.i.c.DefaultManagedHttpClientConnection : http-outgoing-0: set socket timeout to 0
2025-01-15 15:07:57.425 DEBUG 46686 --- [nio-8042-exec-1] h.i.c.PoolingHttpClientConnectionManager : Connection released: [id: 0][route: {}->localhost:9090][total available: 1; route allocated: 1 of 2;  total allocated: 1 of 20]
…
2025-01-15 15:07:57.480 DEBUG 46686 --- [nio-8042-exec-1] o.s.web.servlet.DispatcherServlet        : Completed 200 OK
Журнал запроса №2

Код: Выделить всё

2025-01-15 15:08:21.082 DEBUG 46686 --- [nio-8042-exec-4] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.syed...TestController#testSpringClient()
2025-01-15 15:08:21.084 DEBUG 46686 --- [nio-8042-exec-4] o.s.ws.client.core.WebServiceTemplate    : Opening [org.springframework.ws.transport.http.HttpComponentsConnection@596d45e8] to [localhost:9090/test/ch]
2025-01-15 15:08:21.088 DEBUG 46686 --- [nio-8042-exec-4] o.s.ws.client.MessageTracing.sent        : Sent request [SaajSoapMessage {urn://test.com/xmlmessaging/CH}testEP]
2025-01-15 15:08:21.092 DEBUG 46686 --- [nio-8042-exec-4] o.a.h.client.protocol.RequestAddCookies  : CookieSpec selected: default
2025-01-15 15:08:21.092 DEBUG 46686 --- [nio-8042-exec-4] o.a.h.client.protocol.RequestAuthCache   : Auth cache not set in the context
2025-01-15 15:08:21.092 DEBUG 46686 --- [nio-8042-exec-4] h.i.c.PoolingHttpClientConnectionManager : Connection request: [route: {}->localhost:9090][total available: 1; route allocated: 1 of 2; total allocated: 1 of 20]
2025-01-15 15:08:21.094 DEBUG 46686 --- [nio-8042-exec-4] org.apache.http.wire                     : http-outgoing-0 localhost:9090][total available: 0; route allocated: 1 of 2; total allocated: 1 of 20]
2025-01-15 15:08:21.095 DEBUG 46686 --- [nio-8042-exec-4] h.i.c.DefaultManagedHttpClientConnection : http-outgoing-0: set socket timeout to 120000
…
2025-01-15 15:08:21.096 DEBUG 46686 --- [nio-8042-exec-4] org.apache.http.wire                     : http-outgoing-0 >> "Host: localhost:9090[\r][\n]"
2025-01-15 15:08:21.096 DEBUG 46686 --- [nio-8042-exec-4] org.apache.http.wire                     : http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
2025-01-15 15:08:21.096 DEBUG 46686 --- [nio-8042-exec-4] org.apache.http.wire                     : http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.13)[\r][\n]"
2025-01-15 15:08:21.096 DEBUG 46686 --- [nio-8042-exec-4] org.apache.http.wire                     : http-outgoing-0 >> "Expect: 100-continue[\r][\n]"
2025-01-15 15:08:21.096 DEBUG 46686 --- [nio-8042-exec-4] org.apache.http.wire                     : http-outgoing-0 >> "[\r][\n]"
…
2025-01-15 15:08:21.119 DEBUG 46686 --- [nio-8042-exec-4] org.apache.http.headers                  : http-outgoing-0 http://localhost:9090] can be kept alive for 120.0 seconds
2025-01-15 15:08:21.120 DEBUG 46686 --- [nio-8042-exec-4] h.i.c.DefaultManagedHttpClientConnection : http-outgoing-0: set socket timeout to 0
2025-01-15 15:08:21.120 DEBUG 46686 --- [nio-8042-exec-4] h.i.c.PoolingHttpClientConnectionManager : Connection released: [id: 0][route: {}->http://localhost:9090][total available: 1; route allocated: 1 of 2; total allocated: 1 of 20]
...
2025-01-15 15:08:21.127 DEBUG 46686 --- [nio-8042-exec-4] o.s.web.servlet.DispatcherServlet        : Completed 200 OK
…
2025-01-15 15:09:46.704 DEBUG 46686 --- [nection evictor] h.i.c.PoolingHttpClientConnectionManager : Closing connections idle longer than 120000 MILLISECONDS
2025-01-15 15:11:46.697 DEBUG 46686 --- [nection evictor] h.i.c.PoolingHttpClientConnectionManager : Closing expired connections
2025-01-15 15:11:46.701 DEBUG 46686 --- [nection evictor] org.apache.http.impl.conn.CPool          : Connection [id:0][route:{}->http://localhost:9090][state:null] expired @ Wed Jan 15 15:10:21 CST 2025
2025-01-15 15:11:46.701 DEBUG 46686 --- [nection evictor] h.i.c.DefaultManagedHttpClientConnection : http-outgoing-0: Close connection
При подключении к простой конечной точке HTTP/TCP повторно используется тот же сокет http-outgoing-0. Он закрывается после истечения установленного времени поддержания активности.
Случай 2
Подключение к службе с использованием соединения HTTPS/TLS. .
Код клиента
Код клиента остается прежним, за исключением добавления конфигурации SSL.

Код: Выделить всё

// Load client certificate keystore from resources
KeyStore keyStore = KeyStore.getInstance("JKS");
try (InputStream keyStoreStream = new ClassPathResource("services.jks").getInputStream()) {
keyStore.load(keyStoreStream, "YOUR-PASSWORD".toCharArray());
}

// Load server truststore from resources (if needed)
KeyStore trustStore = KeyStore.getInstance("JKS");
try (InputStream trustStoreStream = new ClassPathResource("services.jks").getInputStream()) {
trustStore.load(trustStoreStream, "YOUR-PASSWORD".toCharArray());
}

SSLContext sslContext = SSLContexts.custom()
.loadKeyMaterial(keyStore, "YOUR-PASSWORD".toCharArray(), (aliases, socket) -> "alias")
.loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) // Trust strategy
.build();

// Create SSLConnectionSocketFactory
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
sslContext,
new String[]{"TLSv1.2"}, // Protocols
null, // Cipher suites (null for default)
SSLConnectionSocketFactory.getDefaultHostnameVerifier()
);

// Create a connection manager with SSL support
Registry socketFactoryRegistry = RegistryBuilder.create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslSocketFactory)
.build();
Журнал запроса №1

Код: Выделить всё

2025-01-15 15:53:03.509 DEBUG 48661 --- [nio-8042-exec-1] .i.c.DefaultHttpClientConnectionOperator : Connection established xxx:53882xxx:443
2025-01-15 15:53:03.509 DEBUG 48661 --- [nio-8042-exec-1] h.i.c.DefaultManagedHttpClientConnection : http-outgoing-0: set socket timeout to 120000
2025-01-15 15:53:03.509 DEBUG 48661 --- [nio-8042-exec-1] o.a.http.impl.execchain.MainClientExec   : Executing request POST /xxx/xxx HTTP/1.1
…
2025-01-15 15:53:03.511 DEBUG 48661 --- [nio-8042-exec-1] org.apache.http.wire                     : http-outgoing-0 >> "Host: xxx[\r][\n]"
2025-01-15 15:53:03.511 DEBUG 48661 --- [nio-8042-exec-1] org.apache.http.wire                     : http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
2025-01-15 15:53:03.511 DEBUG 48661 --- [nio-8042-exec-1] org.apache.http.wire                     : http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.13)[\r][\n]"
…
2025-01-15 15:53:03.723 DEBUG 48661 --- [nio-8042-exec-1] o.a.http.impl.execchain.MainClientExec   : Connection can be kept alive for 120000 MILLISECONDS
…
2025-01-15 15:53:03.731 DEBUG 48661 --- [nio-8042-exec-1] h.i.c.DefaultManagedHttpClientConnection : http-outgoing-0: set socket timeout to 0
2025-01-15 15:53:03.732 DEBUG 48661 --- [nio-8042-exec-1] h.i.c.PoolingHttpClientConnectionManager : Connection released: [id: 0][route: {s}->https://xxx:443][state: CN=*.xxx][total available: 1; route allocated: 1 of 2; total allocated: 1 of 1]
…
2025-01-15 15:53:03.761 DEBUG 48661 --- [nio-8042-exec-1] o.s.web.servlet.DispatcherServlet        : Completed 200 OK
Журнал запроса №2

Код: Выделить всё

2025-01-15 15:53:10.827 DEBUG 48661 --- [nio-8042-exec-4] h.i.c.PoolingHttpClientConnectionManager : Connection request: [route: {s}->https://xxx:443][total available: 1; route allocated: 1 of 2; total allocated: 1 of 1]
2025-01-15 15:53:10.827 DEBUG 48661 --- [nio-8042-exec-4] h.i.c.DefaultManagedHttpClientConnection : http-outgoing-0: Close connection
2025-01-15 15:53:10.830 DEBUG 48661 --- [nio-8042-exec-4] h.i.c.PoolingHttpClientConnectionManager : Connection leased: [id: 1][route: {s}->https://xxx:443][total available: 0; route allocated: 1 of 2; total allocated: 1 of 1]
2025-01-15 15:53:10.830 DEBUG 48661 --- [nio-8042-exec-4] o.a.http.impl.execchain.MainClientExec   : Opening connection {s}->https://xxx:443
2025-01-15 15:53:10.830 DEBUG 48661 --- [nio-8042-exec-4] .i.c.DefaultHttpClientConnectionOperator : Connecting to xxx:443
...
2025-01-15 15:53:10.976 DEBUG 48661 --- [nio-8042-exec-4] .i.c.DefaultHttpClientConnectionOperator : Connection established xxx:53923xxx:443
2025-01-15 15:53:10.976 DEBUG 48661 --- [nio-8042-exec-4] h.i.c.DefaultManagedHttpClientConnection : http-outgoing-1: set socket timeout to 120000
Мы видим, что http-outgoing-0 закрыт и создан http-outgoing-1. Ошибок не возникает.

Код: Выделить всё

2025-01-15 15:56:54.783 DEBUG 48661 --- [nection evictor] h.i.c.PoolingHttpClientConnectionManager : Closing connections idle longer than 120000 MILLISECONDS
2025-01-15 15:56:54.784 DEBUG 48661 --- [nection evictor] org.apache.http.impl.conn.CPool          : Connection [id:1][route:{s}->https://xxx:443][state:CN=*.cert] expired @ Wed Jan 15 15:55:11 CST 2025
2025-01-15 15:56:54.785 DEBUG 48661 --- [nection evictor] h.i.c.DefaultManagedHttpClientConnection : http-outgoing-1: Close connection
2025-01-15 15:56:54.790 DEBUG 48661 --- [nection evictor] h.i.c.PoolingHttpClientConnectionManager : Closing connections idle longer than 120000 MILLISECONDS
Впоследствии соединение закрывается по истечении установленного времени ожидания, если больше не поступает запросов.
Вопрос
  • Почему HTTP-соединение используется повторно, а HTTPS-соединение закрывается и восстанавливается?
  • Как настроить клиент чтобы обеспечить повторное использование соединений и для HTTPS?
  • Есть ли какие-либо конкретные соображения по поводу TLS или пула соединений, которые мне, возможно, не хватает?
Любые идеи и предложения приветствуются. Дайте мне знать, если потребуются дополнительные сведения.

Подробнее здесь: https://stackoverflow.com/questions/793 ... -connectin
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «JAVA»