Я использую Spring WebServiceTemplate
Apache HttpClient
(4.5.3) для выполнения запроса на мыло одному из моих клиентов.Я хочу делать много асинхронных запросов и обрабатывать ответ всякий раз, когда получаю его.
Моя стратегия заключается в том, чтобы использовать один PoolingHttpClientConnectionManager
и делать HttpClientBuilder.setConnectionManager(connectionManager).build()
для каждого запроса.
Но под нагрузкой время отклика начинает замедляться!Я проверил, что клиент все еще отвечает быстро, но sendSourceAndReceiveToResult
слишком долго говорит.Чтобы выяснить, что происходит, я зарегистрировал connectionManager
stats, вот что я получил:
connectionManager.getTotalStats().getAvailable() --> 40
connectionManager.getTotalStats().getLeased() --> 1 only one connection is used to request!
connectionManager.getMaxTotal() --> 200
connectionManager.getDefaultMaxPerRoute() --> 200
Вот мое определение бина
<bean id="myMessageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory" />
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="myMessageFactory" />
<property name="messageSender" ref="messageSender"></property>
</bean>
<bean id="messageSender" class="org.springframework.ws.transport.http.HttpComponentsMessageSender"
</bean>
Мой менеджер соединений
public class CustomPoolingHttpClientConnectionManager extends PoolingHttpClientConnectionManager {
private IdleConnectionMonitorThread monitor;
Logger logger = LoggerFactory.getLogger(CustomPoolingHttpClientConnectionManager.class);
private static final class ConnectionManagerInstanceHolder {
private static final CustomPoolingHttpClientConnectionManager instance = new CustomPoolingHttpClientConnectionManager();
}
private static Registry<ConnectionSocketFactory> getSocketFactoryRegistry() {
SSLConnectionSocketFactory socketFactory = null;
try {
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(
new File(System.getProperty("javax.net.ssl.keyStore")),
System.getProperty("javax.net.ssl.keyStorePassword").toCharArray(),
System.getProperty("javax.net.ssl.keyStorePassword").toCharArray()).build();
socketFactory = new SSLConnectionSocketFactory(
sslcontext,
new String[]{"TLSv1"},
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
}
catch (Exception ex) {
//
}
return RegistryBuilder.<ConnectionSocketFactory> create()
.register("https", socketFactory)
.build();
}
public static CustomPoolingHttpClientConnectionManager getInstance() {
return ConnectionManagerInstanceHolder.instance;
}
public CustomPoolingHttpClientConnectionManager() {
super ( getSocketFactoryRegistry() );
monitor = new IdleConnectionMonitorThread(this);
monitor.start();
}
// Watches for stale connections and evicts them.
private static class IdleConnectionMonitorThread extends Thread {
Logger logger = LoggerFactory.getLogger(IdleConnectionMonitorThread.class);
// The manager to watch.
private final PoolingHttpClientConnectionManager connectionManager;
// Use a BlockingQueue to stop everything.
private final BlockingQueue<Stop> stopSignal = new ArrayBlockingQueue<Stop>(1);
IdleConnectionMonitorThread(PoolingHttpClientConnectionManager cm) {
super();
this.connectionManager = cm;
}
@Override
public void run() {
try {
// Holds the stop request that stopped the process.
Stop stopRequest;
connectionManager.setMaxTotal(200);
connectionManager.setDefaultMaxPerRoute(200);
// Every 5 seconds.
while ((stopRequest = stopSignal.poll(5, TimeUnit.SECONDS)) == null) {
logger.debug("Available Threads: " + connectionManager.getTotalStats().getAvailable() +
"\nCurrently Working Threads: " + connectionManager.getTotalStats().getLeased() +
"\nTotal Thread count: " + connectionManager.getMaxTotal() +
"\nMax Thread per host: " + connectionManager.getDefaultMaxPerRoute());
// Close expired connections
connectionManager.closeExpiredConnections();
// Optionally, close connections that have been idle too long.
connectionManager.closeIdleConnections(20, TimeUnit.SECONDS);
}
// Acknowledge the stop request.
stopRequest.stopped();
} catch (InterruptedException ex) {
// terminate
}
}
// Pushed up the queue.
private static class Stop {
// The return queue.
private final BlockingQueue<Stop> stop = new ArrayBlockingQueue<Stop>(1);
// Called by the process that is being told to stop.
public void stopped() {
// Push me back up the queue to indicate we are now stopped.
stop.add(this);
}
// Called by the process requesting the stop.
public void waitForStopped() throws InterruptedException {
// Wait until the callee acknowledges that it has stopped.
stop.take();
}
}
}
}
Настройка HttpClient
private CloseableHttpClient buildHttpClient() {
HttpClientBuilder builder = HttpClientBuilder.create();
RequestConfig.Builder requestConfig = RequestConfig.custom();
requestConfig.setSocketTimeout(2000);
requestConfig.setConnectionRequestTimeout(2000);
requestConfig.setConnectTimeout(2000);
builder.setDefaultRequestConfig(requestConfig.build());
HttpComponentsMessageSender.RemoveSoapHeadersInterceptor interceptor = new HttpComponentsMessageSender.RemoveSoapHeadersInterceptor();
builder.addInterceptorFirst(interceptor);
builder.setConnectionManager( CustomPoolingHttpClientConnectionManager.getInstance() )
.setConnectionManagerShared(true);
return builder.build();
}
Настройка HttpClient
((HttpComponentsMessageSender) webServiceTemplate.getMessageSenders()[0]).setHttpClient(httpClient);
Я проверяю, закрываю ли CloseableHttpClient
после получения ответа.Но я понятия не имею, почему ответы очень медленные!Что я здесь не так делаю?Любая помощь очень ценится!