From a8ce4d564125fc711f6bab91276667fe40061bec Mon Sep 17 00:00:00 2001 From: Hicham Barhoumi <hicham.barhoumi@archiveco.fr> Date: Fri, 26 Jun 2020 19:16:02 +0200 Subject: [PATCH] [TECH] Add pooling for httpClient for better performance --- .../rest/client/BaseRestClientFactory.java | 34 ++++++++----- ...ttpComponentsClientHttpRequestFactory.java | 48 +++++++++++++++++++ .../RestClientConfiguration.java | 10 ++++ 3 files changed, 81 insertions(+), 11 deletions(-) create mode 100644 commons/commons-rest/src/main/java/fr/gouv/vitamui/commons/rest/client/CustomHttpComponentsClientHttpRequestFactory.java diff --git a/commons/commons-rest/src/main/java/fr/gouv/vitamui/commons/rest/client/BaseRestClientFactory.java b/commons/commons-rest/src/main/java/fr/gouv/vitamui/commons/rest/client/BaseRestClientFactory.java index c241a728..b788f0e1 100644 --- a/commons/commons-rest/src/main/java/fr/gouv/vitamui/commons/rest/client/BaseRestClientFactory.java +++ b/commons/commons-rest/src/main/java/fr/gouv/vitamui/commons/rest/client/BaseRestClientFactory.java @@ -51,6 +51,7 @@ import java.util.List; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; +import fr.gouv.vitamui.commons.rest.client.configuration.RestClientConfiguration; import org.apache.http.HttpHost; import org.apache.http.client.config.RequestConfig; import org.apache.http.config.Registry; @@ -105,20 +106,30 @@ public class BaseRestClientFactory implements RestClientFactory { } public BaseRestClientFactory(final RestClientConfiguration restClientConfig, final HttpPoolConfiguration httpPoolConfig, - final RestTemplateBuilder restTemplateBuilder) { + final RestTemplateBuilder restTemplateBuilder) { Assert.notNull(restClientConfig, "Rest client configuration must be specified"); final boolean useSSL = restClientConfig.isSecure(); baseUrl = RestUtils.getScheme(useSSL) + restClientConfig.getServerHost() + ":" + restClientConfig.getServerPort(); + HttpPoolConfiguration myPoolConfig = httpPoolConfig; + // configure the pool from the restClientConfig if poolMaxTotal is not negative + if(restClientConfig.getPoolMaxTotal() >= 0) { + myPoolConfig = new HttpPoolConfiguration(); + myPoolConfig.setMaxTotal(restClientConfig.getPoolMaxTotal()); + myPoolConfig.setMaxPerRoute(restClientConfig.getPoolMaxPerRoute()); + } + final Registry<ConnectionSocketFactory> csfRegistry = useSSL ? buildRegistry(restClientConfig.getSslConfiguration()) : null; - final PoolingHttpClientConnectionManager connectionManager = buildConnectionManager(httpPoolConfig, csfRegistry); + final PoolingHttpClientConnectionManager connectionManager = buildConnectionManager(myPoolConfig, csfRegistry); final RequestConfig requestConfig = buildRequestConfig(); - final CloseableHttpClient httpClient = HttpClientBuilder.create().setConnectionManager(connectionManager).setDefaultRequestConfig(requestConfig) - .build(); + final CloseableHttpClient httpClient = HttpClientBuilder.create() + .setConnectionManager(connectionManager) + .setDefaultRequestConfig(requestConfig) + .build(); restTemplate = restTemplateBuilder.errorHandler(new ErrorHandler()).build(); - restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient))); + restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(new CustomHttpComponentsClientHttpRequestFactory(httpClient))); } /* @@ -145,7 +156,7 @@ public class BaseRestClientFactory implements RestClientFactory { } sslContext = sslContextBuilder.loadTrustMaterial(new File(ts.getKeyPath()), ts.getKeyPassword().toCharArray()).setProtocol("TLS") - .setSecureRandom(new java.security.SecureRandom()).build(); + .setSecureRandom(new java.security.SecureRandom()).build(); } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException | CertificateException | IOException | UnrecoverableKeyException e) { LOGGER.error("Unable to build the Registry<ConnectionSocketFactory>.", e); @@ -160,7 +171,7 @@ public class BaseRestClientFactory implements RestClientFactory { } private KeyStore loadPkcs(final String type, final String filename, final char[] password) - throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException { + throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException { final KeyStore keyStore = KeyStore.getInstance(type); final File key = ResourceUtils.getFile(filename); try (InputStream in = new FileInputStream(key)) { @@ -176,12 +187,13 @@ public class BaseRestClientFactory implements RestClientFactory { * from the pool rather than creating a brand new connection. */ private PoolingHttpClientConnectionManager buildConnectionManager(final HttpPoolConfiguration poolConfig, - final Registry<ConnectionSocketFactory> socketFactoryRegistry) { + final Registry<ConnectionSocketFactory> socketFactoryRegistry) { final PoolingHttpClientConnectionManager connectionManager = (socketFactoryRegistry != null) - ? new PoolingHttpClientConnectionManager(socketFactoryRegistry) - : new PoolingHttpClientConnectionManager(); + ? new PoolingHttpClientConnectionManager(socketFactoryRegistry) + : new PoolingHttpClientConnectionManager(); + LOGGER.debug("Pool configuration {}", poolConfig); if (poolConfig != null) { connectionManager.setMaxTotal(poolConfig.getMaxTotal()); // Default max per route is used in case it's not set for a specific route @@ -198,7 +210,7 @@ public class BaseRestClientFactory implements RestClientFactory { private RequestConfig buildRequestConfig() { return RequestConfig.custom().setConnectionRequestTimeout(connectionRequestTimeout).setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout) - .build(); + .build(); } @Override diff --git a/commons/commons-rest/src/main/java/fr/gouv/vitamui/commons/rest/client/CustomHttpComponentsClientHttpRequestFactory.java b/commons/commons-rest/src/main/java/fr/gouv/vitamui/commons/rest/client/CustomHttpComponentsClientHttpRequestFactory.java new file mode 100644 index 00000000..86b62ec6 --- /dev/null +++ b/commons/commons-rest/src/main/java/fr/gouv/vitamui/commons/rest/client/CustomHttpComponentsClientHttpRequestFactory.java @@ -0,0 +1,48 @@ +package fr.gouv.vitamui.commons.rest.client; + +import fr.gouv.vitamui.commons.api.logger.VitamUILogger; +import fr.gouv.vitamui.commons.api.logger.VitamUILoggerFactory; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.protocol.HttpContext; +import org.springframework.http.HttpMethod; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.apache.http.client.HttpClient; +import java.net.URI; + +/** + * Custom HttpComponentsClientHttpRequestFactory to override createContext + */ +public class CustomHttpComponentsClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory { + + private static final VitamUILogger LOGGER = VitamUILoggerFactory.getInstance(CustomHttpComponentsClientHttpRequestFactory.class); + + /** + * default construct + */ + public CustomHttpComponentsClientHttpRequestFactory() { + super(); + } + + /** + * construct with httpClient + * @param httpClient + */ + public CustomHttpComponentsClientHttpRequestFactory(HttpClient httpClient) { + super(httpClient); + } + + /** + * Create the httpContext and init with a userToken + * @param httpMethod + * @param uri + * @return + */ + @Override + protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) { + LOGGER.debug("Context creation"); + HttpContext context = HttpClientContext.create(); + context.setAttribute(HttpClientContext.USER_TOKEN, "fake_user_token_value"); + return context; + } + +} diff --git a/commons/commons-rest/src/main/java/fr/gouv/vitamui/commons/rest/client/configuration/RestClientConfiguration.java b/commons/commons-rest/src/main/java/fr/gouv/vitamui/commons/rest/client/configuration/RestClientConfiguration.java index 1299fb58..59d762fe 100644 --- a/commons/commons-rest/src/main/java/fr/gouv/vitamui/commons/rest/client/configuration/RestClientConfiguration.java +++ b/commons/commons-rest/src/main/java/fr/gouv/vitamui/commons/rest/client/configuration/RestClientConfiguration.java @@ -77,4 +77,14 @@ public class RestClientConfiguration { * Write timeout in seconds. */ private int writeTimeOut = 10; + + /** + * total pool size for httpClient + */ + private int poolMaxTotal = 10; + + /** + * pool size per route(host) + */ + private int poolMaxPerRoute = 10; } -- GitLab